Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 06-11-2011, 04:35 AM   #1 (permalink)
Registered Member
 
Join Date: Jun 2011
Posts: 8
zaikshev88 is on a distinguished road
Default Objective C: App getting Memory Warning Level 2 and exits shortly after

My app grabs photo images from a server and stores them in an array which will eventually be displayed in a UITableView Controller.

I am displaying 2 images in a single cell (768 by 768 pixels and 100 X 100 pixels).

At launch, the app will load 10 cells with images and the user can choose to load the next 10 photos using a "load more" button. Usually after 15-20 'load more' clicks, I will receive a memory warning level = 2 message and my app will just terminate.

Is this due to the fact that there are too many images displayed? How can I resolve this issue?
zaikshev88 is offline   Reply With Quote
Old 06-11-2011, 04:38 AM   #2 (permalink)
Just helping out.
 
Domele's Avatar
 
Join Date: Feb 2011
Posts: 2,565
Domele is on a distinguished road
Default

I don't have experience just from what I've read. Large images will consume a lot of memory. Unless the user is on an iPad there is not reason to have images that big. You also need to learn to lazy load more. Only load when you have to. Maybe someone who has displayed big images can talk to you more in depth about your situation.
Domele is offline   Reply With Quote
Old 06-11-2011, 04:45 AM   #3 (permalink)
Registered Member
 
Join Date: Jun 2011
Posts: 8
zaikshev88 is on a distinguished road
Default

Hi Domele, interesting thing is that I have already implemented lazy loading of my images. It still gives me a memory warning level 2 message
zaikshev88 is offline   Reply With Quote
Old 06-11-2011, 06:00 AM   #4 (permalink)
mr.
 
refreshe's Avatar
 
Join Date: Jul 2008
Location: SF, California | Melbourne, Australia
Posts: 346
refreshe is on a distinguished road
Default

Is your array of images always in memory? If it is, then you will eventually crash as it grows too large. When dealing with large images, you might want to save them to disk and load them as needed (when cells become visible) instead of having them all in memory at once. At the least, handle the memory warning by remove non-visible images from memory when it's triggered.
__________________
appz
refreshe is offline   Reply With Quote
Old 06-11-2011, 09:43 AM   #5 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by zaikshev88 View Post
My app grabs photo images from a server and stores them in an array which will eventually be displayed in a UITableView Controller.

I am displaying 2 images in a single cell (768 by 768 pixels and 100 X 100 pixels).

At launch, the app will load 10 cells with images and the user can choose to load the next 10 photos using a "load more" button. Usually after 15-20 'load more' clicks, I will receive a memory warning level = 2 message and my app will just terminate.

Is this due to the fact that there are too many images displayed? How can I resolve this issue?

When you click your "load more" button, how are you releasing the old images before loading new ones? You should probably post the relevant code.

Either you're keeping them in an array and not releasing them at all, or you have an extra retain (explicit or implicit) somewhere, and you are leaking the images. Try running your app with the leaks and memory allocation instruments. I bet you'll find that every time you click the more button, your memory usage grows, until you run out.
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 06-11-2011, 10:36 AM   #6 (permalink)
Registered Member
 
Join Date: Jun 2011
Posts: 8
zaikshev88 is on a distinguished road
Default

Hi basically I am using the code below to retrieve and store my photos. Every time I click 'load more', the array basically grows (with 10 photo objects more each time). Is there a way to control memory usage for this case? In fact I am only storing the profile image and not the actual sized photos (only URL stored)

Code:
- (void)preloadPhotoData
{   
    self.returnCount = 0;
    UIDevice *myDevice = [UIDevice currentDevice];
	NSString *deviceUDID = [myDevice uniqueIdentifier];
    
    self.urlString = [NSString stringWithFormat:@"http://myURL.com/photos.json?device_id=%@&page=%i&per_page=%i&type=%@",deviceUDID,self.pageNum,kPhotosPerPage,self.type];
    
    NSString *loadingString = [NSString stringWithFormat:@"Loading data from Instahotness....."];
    self.loadingPage.loadingTextLabel.text = loadingString;
    [self fetchJSONFile];
}

-(void)fetchJSONFile
{    
    NSURL *url = [NSURL URLWithString:self.urlString];
    
    __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
    [request setCompletionBlock:^{
        
        // Use when fetching text data
        NSString *responseString = [request responseString];
        
        NSError *error;
        SBJsonParser *json = [[SBJsonParser new]autorelease];
        self.jsonArray = [json objectWithString:responseString error:&error];
        
        if (self.jsonArray == nil) 
        {
            NSString *errorString = [NSString stringWithFormat:@"JSON parsing failed: %@", [error localizedDescription]];
            NSLog(@"%@",errorString);
            [self errorHanding];        
        }
        else
        {
            NSString *createPhotoString = [NSString stringWithFormat:@"Loading Profile Pictures....."];
            self.loadingPage.loadingTextLabel.text = createPhotoString;
            [self createPhotoArray];
        }
        
        
    }];
    [request setFailedBlock:^{
        NSError *error = [request error];
        NSString *connectionErrString = [NSString stringWithFormat:@"Error Loading Profile Pic: %@", [error description]];
        NSLog(@"%@",connectionErrString);
        
        [self errorHanding];

    }];
    [request startAsynchronous];

}

-(void)createPhotoArray
{
    
    for (int i =0; i<[self.jsonArray count]; i++) 
    {
        NSDictionary *aPhoto = [self.jsonArray objectAtIndex:i];
        NSString *pid = [aPhoto valueForKey:@"pid"];
        NSString *userName = [aPhoto valueForKey:@"user_username"];
        NSString *userFullName = [aPhoto valueForKey:@"user_full_name"];
        NSString *userBio = [aPhoto valueForKey:@"user_bio"];
        NSString *caption = [aPhoto valueForKey:@"caption"];
        NSString *profileImageURL = [aPhoto valueForKey:@"user_profile_picture"];
        NSString *standardPhotoURL = [aPhoto valueForKey:@"standard_resolution"];
        NSString *isStarred = [aPhoto valueForKey:@"photoIsStarred"];
        NSString *thisStarCount = [aPhoto valueForKey:@"star_count"];
        
        BOOL photoIsStarred = [isStarred boolValue];
        NSUInteger starCount = [thisStarCount intValue];

        
        Photo *newPhoto = [[[Photo alloc]initWithPid:pid
                                            UserName:userName 
                                             userBio:userBio 
                                        userFullName:userFullName 
                                             caption:caption 
                                     profileImageURL:profileImageURL 
                                        profileImage:nil
                                      profilePicSize:CGSizeZero 
                                               image:standardPhotoURL 
                                           imageSize:CGSizeZero
                                      photoIsStarred:photoIsStarred
                                           starCount:starCount]autorelease];
        
        [self.photoArray addObject:newPhoto];  
    }
    
    [self fetchPhotoImage];

}

Last edited by zaikshev88; 06-11-2011 at 10:53 AM.
zaikshev88 is offline   Reply With Quote
Old 06-11-2011, 10:47 AM   #7 (permalink)
Just helping out.
 
Domele's Avatar
 
Join Date: Feb 2011
Posts: 2,565
Domele is on a distinguished road
Default

Use code tags please. [code] [/1CODE] Without the one.
Domele is offline   Reply With Quote
Old 06-11-2011, 10:53 AM   #8 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by zaikshev88 View Post
Hi basically I am using the code below to retrieve and store my photos. Every time I click 'load more', the array basically grows (with 10 photo objects more each time). Is there a way to control memory usage for this case? In fact I am only storing the profile image and not the actual sized photos (only URL stored)

- (void)preloadPhotoData
{
self.returnCount = 0;
UIDevice *myDevice = [UIDevice currentDevice];
NSString *deviceUDID = [myDevice uniqueIdentifier];

self.urlString = [NSString stringWithFormat:@"http://myURL.com/photos.json?device_id=%@&page=%i&per_page=%i&type= %@",deviceUDID,self.pageNum,kPhotosPerPage,self.ty pe];

NSString *loadingString = [NSString stringWithFormat:@"Loading data from Instahotness....."];
self.loadingPage.loadingTextLabel.text = loadingString;
[self fetchJSONFile];
}

-(void)fetchJSONFile
{
NSURL *url = [NSURL URLWithString:self.urlString];

__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{

// Use when fetching text data
NSString *responseString = [request responseString];

NSError *error;
SBJsonParser *json = [[SBJsonParser new]autorelease];
self.jsonArray = [json objectWithString:responseString error:&error];

if (self.jsonArray == nil)
{
NSString *errorString = [NSString stringWithFormat:@"JSON parsing failed: %@", [error localizedDescription]];
NSLog(@"%@",errorString);
[self errorHanding];
}
else
{
NSString *createPhotoString = [NSString stringWithFormat:@"Loading Profile Pictures....."];
self.loadingPage.loadingTextLabel.text = createPhotoString;
[self createPhotoArray];
}


}];
[request setFailedBlock:^{
NSError *error = [request error];
NSString *connectionErrString = [NSString stringWithFormat:@"Error Loading Profile Pic: %@", [error description]];
NSLog(@"%@",connectionErrString);

[self errorHanding];

}];
[request startAsynchronous];

}

-(void)createPhotoArray
{

for (int i =0; i<[self.jsonArray count]; i++)
{
NSDictionary *aPhoto = [self.jsonArray objectAtIndex:i];
NSString *pid = [aPhoto valueForKey:@"pid"];
NSString *userName = [aPhoto valueForKey:@"user_username"];
NSString *userFullName = [aPhoto valueForKey:@"user_full_name"];
NSString *userBio = [aPhoto valueForKey:@"user_bio"];
NSString *caption = [aPhoto valueForKey:@"caption"];
NSString *profileImageURL = [aPhoto valueForKey:@"user_profile_picture"];
NSString *standardPhotoURL = [aPhoto valueForKey:@"standard_resolution"];
NSString *isStarred = [aPhoto valueForKey:@"photoIsStarred"];
NSString *thisStarCount = [aPhoto valueForKey:@"star_count"];

BOOL photoIsStarred = [isStarred boolValue];
NSUInteger starCount = [thisStarCount intValue];


Photo *newPhoto = [[[Photo alloc]initWithPidid
UserName:userName
userBio:userBio
userFullName:userFullName
caption:caption
profileImageURLrofileImageURL
profileImage:nil
profilePicSize:CGSizeZero
image:standardPhotoURL
imageSize:CGSizeZero
photoIsStarredhotoIsStarred
starCount:starCount]autorelease];

[self.photoArray addObject:newPhoto];
}

[self fetchPhotoImage];

}
Your method createPhotoArray creates an array of Photo objects and saves it in self.photoArray. Presumably photoArray is a retained property, so that array is being retained. What does a Photo object contain?

You then call a method fetchPhotoImage. What does that method do? The name suggests that it loads photo images.

Where is the code that is actually loading the images from the server and installing them into your UIImageViews? That's where your memory problems are going to originate.
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 06-11-2011, 10:57 AM   #9 (permalink)
Registered Member
 
Join Date: Jun 2011
Posts: 8
zaikshev88 is on a distinguished road
Default

Hi Duncan, yes the code below basically retrieves the profile images from the server and stores them in the photo object. This is the only image I am storing. This array will then be used by the tableview controller for display. Can you advise me how I can store the profile images such that I do not cause memory issues?

Code:
-(void)fetchPhotoImage
{
    for (int i=0; i<[self.photoArray count]; i++) 
    {
        Photo *thisPhoto = [self.photoArray objectAtIndex:i];
        NSString *profileImageURL = thisPhoto.profileImageURL;
        
        NSURL *url = [NSURL URLWithString:profileImageURL];
        __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
        [request setCompletionBlock:^{
            
            // Use when fetching binary data
            NSData *responseData = [request responseData];
            UIImage *profilePhotoImage = [UIImage imageWithData:responseData];
            thisPhoto.profileImage = profilePhotoImage;
            
            self.returnCount++;
            NSLog(@"Profile image %@", thisPhoto.profileImage);
            
            [self arrayIsComplete];
            
        }];
        [request setFailedBlock:^{
            NSError *error = [request error];
            NSString *connectionErrString = [NSString stringWithFormat:@"Connection failed: %@", [error description]];
            NSLog(@"%@",connectionErrString);
        }];
        [request startAsynchronous];
    }
}
zaikshev88 is offline   Reply With Quote
Old 06-11-2011, 01:58 PM   #10 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by zaikshev88 View Post
Hi Duncan, yes the code below basically retrieves the profile images from the server and stores them in the photo object. This is the only image I am storing. This array will then be used by the tableview controller for display. Can you advise me how I can store the profile images such that I do not cause memory issues?

Code:
-(void)fetchPhotoImage
{
    for (int i=0; i<[self.photoArray count]; i++) 
    {
        Photo *thisPhoto = [self.photoArray objectAtIndex:i];
        NSString *profileImageURL = thisPhoto.profileImageURL;
        
        NSURL *url = [NSURL URLWithString:profileImageURL];
        __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
        [request setCompletionBlock:^{
            
            // Use when fetching binary data
            NSData *responseData = [request responseData];
            UIImage *profilePhotoImage = [UIImage imageWithData:responseData];
            thisPhoto.profileImage = profilePhotoImage;
            
            self.returnCount++;
            NSLog(@"Profile image %@", thisPhoto.profileImage);
            
            [self arrayIsComplete];
            
        }];
        [request setFailedBlock:^{
            NSError *error = [request error];
            NSString *connectionErrString = [NSString stringWithFormat:@"Connection failed: %@", [error description]];
            NSLog(@"%@",connectionErrString);
        }];
        [request startAsynchronous];
    }
}

I haven't used ASIHTTPRequest before. Can you set it up to download your images directly to files?

I would suggest reworking your code so you download each image and save it to a file in your documents directory. Save the filename in your Photo object.

Then make your table view load the image from a file and install the image in a table view cell after dequeuing/creating a cell (in your cellForRowAtIndexPath method) Set it up so only the table view cell's UIImageView retains the image. Then, when the cell scrolls offscreen and is reused, the old image will be released.
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Reply

Bookmarks

Tags
ios, memory, objective-c

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 315
7 members and 308 guests
chemistry, Dnnake, iOS.Lover, jenniead38, lendo, Leslie80, pbart
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,664
Threads: 94,120
Posts: 402,898
Top Poster: BrianSlick (7,990)
Welcome to our newest member, Leslie80
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 02:22 AM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0