Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding UIImage to NSMutable array for an animation

I have an app that creates an animation from images stored in a group in my project navigator (not Images.xcassets). This code "works" in that it animates properly, but using imageNamed causes a memory leak because the image files are not getting deallocated.

I can't figure out why adding with imageNamed: works adds images to my array, but imageWithContentsOfFile: doesn't.

A little info on the mechanics of my app:

self.myPhoto is set on the segue from another ViewController. The number of images can vary, so I test to see the file is "there" before adding it to the array.

Filenames follow this naming convention:

"1-1.jpg"
"2-1.jpg"
"2-2.jpg"
"99-1.jpg"
"99-2.jpg"
"99-3.jpg"
"99-4.jpg"

This code works, but the images don't deallocate, causing a memory leak:

- (void)startAnimation {

    NSMutableArray *imageArray = [[NSMutableArray alloc] init];

    for (int imageNumber = 1; self.myPhoto != nil; imageNumber++) {
        NSString *fileName = [NSString stringWithFormat:@"%@-%d.jpg", self.myPhoto, imageNumber];

        // check if a file exists
        if ([UIImage imageNamed:fileName]) {
            // if it exists, add it to the array
            [imageArray addObject:[UIImage imageNamed:fileName]];
        } else {
            // otherwise, don't add image to the array
            break;
        }
    }

    self.myImageView.animationImages = imageArray;
    self.myImageView.animationDuration = 1.5f;
    self.myImageView.animationRepeatCount = 0;
    self.myImageView.contentMode = UIViewContentModeScaleAspectFit;
    [self.myImageView startAnimating];

}

I ran Instruments on it and saw I had a memory leak emanating from my animation. Digging around a little on StackOverflow, I discovered the manner I'm adding my files to myArray results in images not getting deallocated.

So I tried this, instead:

- (void)startAnimation {

    NSMutableArray *imageArray = [[NSMutableArray alloc] init];

    for (int imageNumber = 1; self.myPhoto != nil; imageNumber++) {
        NSString *fileName = [NSString stringWithFormat:@"%@-%d", self.myPhoto, imageNumber];

        // check if a file exists
        if ([UIImage imageNamed:fileName]) {
            // if it exists, add it to the array
            [imageArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:[NSString stringWithFormat:@"%@", fileName] ofType:@"jpg"]]];
            NSLog(@"%@ added to imageArray", fileName);
        } else {
            // otherwise, don't add image to the array
            break;
        }
    }

    NSLog(@"There are %lu images in imageArray", (unsigned long)imageArray.count);

    self.myImageView.animationImages = imageArray;
    self.myImageView.animationDuration = 1.5f;
    self.myImageView.animationRepeatCount = 0;
    self.myImageView.contentMode = UIViewContentModeScaleAspectFit;
    [self.myImageView startAnimating];

}

When I do it this way, the page where the animation loads appears, but the images don't get added to my array--the . This is a well-documented issue. Here are a few posts covering this problem:

Dirty Memory because of CoreAnimation and CG image

How do I use imageWithContentsOfFile for an array of images used in an animation?

Thank you for reading. I'm stumped, though I'm confident the resolution to this problem is a startlingly stupid oversight on my part. Prove me right ;)

like image 952
Adrian Avatar asked Apr 25 '26 08:04

Adrian


1 Answers

I made some minor changes out of desperation and I stumbled into the "answer". Comments note where I made changes:

- (void)startAnimation {

    NSMutableArray *imageArray = [[NSMutableArray alloc] init];

    for (int imageNumber = 1; self.myPhoto != nil; imageNumber++) {
        // I set the filename here, adding .jpg to it
        NSString *fileName = [NSString stringWithFormat:@"%@-%d.jpg", self.myPhoto, imageNumber];

        // check if a file exists
        if ([UIImage imageNamed:fileName]) {
            // if it exists, add it to the array
            // I blanked out ofType, as it's set when I create the local fileName variable
            [imageArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:[NSString stringWithFormat:@"%@", fileName] ofType:@""]]];
        } else {
            // otherwise, don't add image to the array
            break;
        }
    }

    self.myImageView.animationImages = imageArray;
    self.myImageView.animationDuration = 1.5f;
    self.myImageView.animationRepeatCount = 0;
    self.myImageView.contentMode = UIViewContentModeScaleAspectFit;
    [self.myImageView startAnimating];

}
like image 80
Adrian Avatar answered Apr 27 '26 23:04

Adrian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!