user3155084
user3155084

Reputation: 23

NSArray received memory warning

I have an array of images that changes to a random image with an IBAction attached to a button when pressed. When run on a simulator it runs fine but on a device it seems to crash after memory warnings. It also lags when the button is pressed. I want it to run smoothly, and not crash. I believe this has something to do with my array not releasing each image. Here is my array inside my buttons code.

-(IBAction)buttonPressed:(id)sender;
{

     int ptr = arc4random() % 132;

    NSArray* images = [[NSArray alloc] initWithObjects:@"17",@"29",@"55",@"400",@"Alcohol",@"Arianny",@"Anderson",@"Approach",@"Arab",@"Asian",@"Attitude",@"Attraction",@"Beckinsale",@"Blueberry",@"Brain",@"Break",@"Breakups",@"Burns",@"Buttocks",@"Charity",@"Check",@"Chicago",@"Chocolate",@"Coco",@"Coffee",@"College",@"Commit",@"Common",@"Confident",@"Cook",@"Count",@"Country",@"Couples",@"Courtship",@"Criminal",@"Cruz",@"Date",@"Date14",@"Deed",@"Degree",@"Dropped",@"Dushku",@"Dworaczyk",@"Eating",@"Emotion",@"Exercise",@"Fwb",@"Fantasies",@"Fitness",@"Flings",@"Flirt",@"Foot",@"Forget",@"Friendship",@"Frowning",@"Hum",@"Impression",@"Hair",@"Happiness",@"Hazel",@"Headache",@"Instant",@"Interest",@"Internet",@"Jacobs",@"January",@"Jimena",@"Jolie",@"Kalia",@"Kardashian",@"Kiss",@"Kissing",@"Krupa",@"Larissa",@"Latino",@"Laughter",@"Lip",@"London",@"Love",@"Love2",@"Love3",@"Love4",@"Math",@"Maximus",@"Melany",@"Memory",@"Men",@"Milian",@"Miller",@"Millions",@"Mind",@"Monica",@"Muscle",@"Partner",@"Naps",@"Negativity",@"Novels",@"Oral",@"Ossa",@"Pain",@"Positions",@"Productive",@"Proximity",@"Read",@"Reputation",@"Second",@"Sensitive",@"Serious",@"Shaking",@"Sleep2",@"Smile",@"Smoke",@"Smoke2",@"Smokers",@"Sneeze",@"Socks",@"Sold",@"Spot",@"Stimuli",@"Stone",@"Survey",@"Swell",@"Tattoo",@"Teacher",@"Teeth",@"Vickers",@"Violence",@"Wallet",@"Weight",@"Windmills.png",@"White",@"Women",@"Yawn",nil];


    [imageView setImage:[UIImage imageNamed:[images objectAtIndex:ptr]]];
    ptr++;
    NSLog(@"button pressed");

}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.images=nil;

}

- (void)dealloc {

    [images release];
    [adView release];

    [super dealloc];
}

Upvotes: 0

Views: 288

Answers (3)

Becca Royal-Gordon
Becca Royal-Gordon

Reputation: 17861

You actually have two problems here, both surrounding this line:

NSArray* images = [[NSArray alloc] initWithObjects: ...strings omitted... ,nil];

The first is that the NSArray* at the beginning of the line declares a new local variable, images. This is separate from the property self.images that you try to erase in -viewDidUnload and release in -dealloc. Removing the NSArray* from the line will fix this issue, storing the array into the self.images property as you seem to intend.

That gives you a line like this:

images = [[NSArray alloc] initWithObjects: ...strings omitted... ,nil];

The second problem is that you re-create the images array each time you go through this method. That means that, even if you fixed the first problem, you would still be throwing away the old array without releasing it each time you passed through the method, so you'd still be leaking these arrays. There are a bunch of ways you could fix this, but the easiest one is probably to simply test if you already have an array and only create it if you haven't:

if(!images) {
    images = [[NSArray alloc] initWithObjects: ...strings omitted... ,nil];
}

(Since all instances of this class have an identical list of image names, you could instead store the array in a static variable so it'd be shared between them—perhaps initialized by calling dispatch_once—but this isn't likely to make a difference unless you have many instances of this view controller on screen at the same time.)

Upvotes: 1

TotoroTotoro
TotoroTotoro

Reputation: 17622

First off, use ARC, if you can.

You have 2 things leaking memory: the image and the array of image names. Since the image names are constant, you only need to create this array once.

Create ivars for the image and for the image name array: UIImage *_image; NSArray *_imageNames; // init this in your viewDidLoad:

Then, in your button press handler:

-(IBAction)buttonPressed:(id)sender;
{
     int ptr = arc4random() % 132;

    [_image release];
    _image = UIImage imageNamed:_images[ptr]];
    [imageView setImage:_image];
    ptr++;
    NSLog(@"button pressed");
}

Finally, release _imageNames:

- (void)dealloc
{
    [_imageNames release];
    // release everything else.
}

Again, you should really consider switching to ARC. You'll be glad you did.

Upvotes: 1

kjhkjhkjh
kjhkjhkjh

Reputation: 410

As I see your code is not running with ARC so when you create images array it is not deleted from memory until you call release. write release after you don't need your array anymore:

int ptr = arc4random() % 132;
NSArray* images = [[NSArray alloc] initWithObjects:@"17",@"29"];
[imageView setImage:[UIImage imageNamed:[images objectAtIndex:ptr]]];
ptr++;
[images release];

Upvotes: 2

Related Questions