Reputation: 572
i have iPhone application. In some cases, when the device is getting low on free memory, some actions (for example, opening the camera) might cause the application to crash.
My question is that:
EDIT: I ask this question assuming i already implement the 'didReceiveMemoryWarning' function and freed all the memory i can.
EDIT 2: my app is about pictures. A lot like camera scanner apps, this app allows taking pictures, image processing and saving data about them in memory. my crashes usually happens when i scan a lot of pictures.
Upvotes: 1
Views: 1412
Reputation: 4111
Some thumb rules i follow:
Using Arc
Use weak for iboutlets (except top level example: UIwindow) and for delegates
Use Strong for class properties and copy for NSString.
Dont access variables directly, use self....way.
Dont use autorelease way of creating new objects, example NSArray *array = [NSArray arrayWithObjects......., instead use NSArray *array = [NSArray alloc] initWit....
Same way for NSString class. try to use [NSString alloc] initWithFormat..... instead of [NSString stringWithFormat.
When ever you are adding NSNotification(addObserver...) centre must remove(removeObserver..) them in dealloc.
Implement didReceiveMemoryWarning(view controller level) or applicationDidReceiveMemoryWarning(application level and it is called first than view controller level) properly, how ever there are times when you only and only wish to save from crash.you can display an alert telling user less memory available, you can pop/present ..user to home screen.(Bad practice).
Dont perform any manipulation on main thread while being in background thread.Always use @autorelease block for background threads.
use GCD/NSOperation queue for long running processes.
Keep an sharp eye on image resources you are using, use image only of desired size not scale big image to small image size for your need.
USE autorelease pool for long running loops, which create a lot of autoreleased objects.
i have some code snippet for you which ypu can follow:
//way 1 all on main thread bad approach, basically we are just doing some image manipulation on main thread(should not do on main thread :))
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
YourApplicationDelegate *appDelegate = (YourApplicationDelegate *)[[UIApplication sharedApplication]delegate];
[appDelegate showLandscapeLoading];//think it as progress view/loader
UIImage *pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *imageData = UIImagePNGRepresentation(pickedImage);
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"category_imagename.jpeg"];
NSError * error = nil;
//from here
[imageData writeToFile:path options:NSDataWritingAtomic error:&error];
**//the important part for discussion UI manipulation on main thread bad bad bad**
CGSize size1;//A
size1.width = 400;
size1.height = 400;
UIGraphicsBeginImageContext(size1);
[pickedImage drawInRect:CGRectMake(0, 0, size1.width, size1.height)];
UIImage *bigImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSString *bigThumb = [documentsDirectory stringByAppendingPathComponent:@"category_thumb_imagename.jpeg"];
NSData *data1=UIImageJPEGRepresentation(bigImage, 0.5);
BOOL status1=[data1 writeToFile:bigThumb atomically:YES];
**//up to here should be in non ui thread/seperate thread**
**//below code should go in main thread**
NSLog(@"status1 -> %d",status1);
[self setCategoryImageName:bigImage];
[self.imgCategory setImage:pickedImage];
if (status1) {
isAddingCategoryImage = YES;
}
[appDelegate stopLandscapeLoading];
if (error != nil) {
NSLog(@"Error: %@", error);
return;
}
if ([self.popoverController isPopoverVisible]) {
[self.popoverController dismissPopoverAnimated:true];
}
[picker.view removeFromSuperview];
}
The correct way:
Using NSOperation:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
YourApplicationDelegate *appDelegate = (YourApplicationDelegate *)[[UIApplication sharedApplication]delegate];
[appDelegate showLandscapeLoading];
UIImage *pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSError * error = nil;
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperationWithBlock:^
{
// Create a graphics image context very slow stuff
CGSize newSize = CGSizeMake(400, 400);
UIGraphicsBeginImageContext(newSize);
// Tell the old image to draw in this new context, with the desired
// new size
[pickedImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
// Get the new image from the context
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
// End the context
UIGraphicsEndImageContext();
NSString *bigThumb = [documentsDirectory stringByAppendingPathComponent:@"category_thumb_imagename.jpeg"];
NSData *data1=UIImageJPEGRepresentation(newImage, 0.5);
BOOL status1=[data1 writeToFile:bigThumb atomically:YES];
// ok, now do UI stuff in the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
[self setCategoryImageName:bigThumb];
[self.imgCategory setImage:pickedImage];
if (status1) {
isAddingCategoryImage = YES;
}
[appDelegate stopLandscapeLoading];
if (error != nil) {
NSLog(@"Error: %@", error);
return;
}
if ([self.popoverController isPopoverVisible]) {
[self.popoverController dismissPopoverAnimated:true];
}
[picker.view removeFromSuperview];
}];
}];
}
thanks and regards, ALOK
Upvotes: 4
Reputation: 112
If you use non arc and You had allocated the many object and you did not release these object so it shows the memory problem. you relase all object in dealloc method.In goes upper product option and choose the Analyze. you will see where your application memory leak
If you have used old xcode and you have use new iphone simulator than it shows the memory leak
If you use arc than please comment the autorelease or [obj release] close.
Further than if you want to check their application than side corner button to hold and choose profile. it will show instruments tools. you can enable Nszombies. than you can check how to object values have take and you can see where the memory leak in your application.
Upvotes: 1
Reputation: 26383
The memory warning system had a lot of improvements since I started to develop for iOS, ARC also works great helping developers managing memory.
You should profile your app using leaks and allocations to see why your app is consuming so much memory.
Which kind of application are you developing? should be a high memory usage application such as games, or photos app?
A crash could be due to a not well managed answer to a memory warning or to a huge memory occupation that doesn't leave any last breath to your app.
The most common reason are pictures. These devices can't handle a lot of hires resources if you don't manage those situations in the right way, the memory footprint of your app grows until it can't free enough memory.
You need to give more details, though.
Upvotes: 0
Reputation: 13783
No there are is no direct call to free RAM memory in iOS. If you use ARC in your project, define your properties as weak/strong etc correctly and have checked your application for memory leaks or zombie processes there will not be a RAM issue.
iOS frees up memory from other apps to allocate it it to the foreground app if needed and you should not try to deal with it. If you app crashes due to memory issues, you probably have a memory leak in your application. Use Instruments to profile your app.
Upvotes: 0