Why does methods that run in the background using performSelectorInBackground create lot of memory leaks?
Thanks.
Create an NSAutoReleasePool for the background thread.
Add this at the start of your called method
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
and at the end:
[pool release];
Check Apple's documentation about NSAutoReleasePools.
Related
I want to use the auto-release in my apps. I want to implement this methods
- (void)selectorConnect: (NSArray *)args
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//some code
[pool release];
}
Getting crash at [pool release] line. Any solution for that .
When you empty an autorelease pool, it calls autorelease on all objects inside it.
If you're getting a crash with the [pool release] line then you've added an object to the autorelease pool and have released it yourself.
Run the static analyser and see what warnings it gives you.
And if you still don't know, enable NSZombies and see what object is being released twice.
Finally, if that still doesn't help, add your code to the question and we can all take a look :)
I am downloading data from my server it is taking like 5 to 6 minutes for downloading..while downloading I am not able to do any work in my application. How to send downloading process on background so that user can navigate within application and after download. we will inform user downloading completed..
Thank you.
Create the new thread:
[NSThread detachNewThreadSelector:#selector(myMethod)
toTarget:self
withObject:nil];
Create the method that is called by the new thread:
- (void)myMethod
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/*** code that should be run in the new thread goes here ***/
[pool release];
}
What if you need to do something to the main thread from inside your new thread (for example, show a loading symbol)? Use performSelectorOnMainThread.
[self performSelectorOnMainThread:#selector(myMethod)
withObject:nil
waitUntilDone:false];
What you need to do is have your downloading code on a separate thread (NSThread on iOS). Here's a tutorial to get you started.
So this has been confusing me for a while. I am running my app in the "Profile" Mode trying to find memory leaks in my app. I think I got all of them expect when I click on the Map part of my application it reports back that a reference to NSAutoreleasePool was leaked from the Foundation Library. I check the trace of the object but it only reports back from the method allocWithZone. It seems to leak only once on matter how many times I alloc and dealloc that view controller. I did a search of my code and the only reference I make to NSAutoreleasePool is in the main.m file. Is this an Apple bug (which I doubt) or am I doing something wrong?
main.m
#import <UIKit/UIKit.h>
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
Looks like it was an Apple bug. The same amount of memory is leaked in the other question which leads me to believe they are the same bug. I did an extensive code audit and nothing seemed to be working to get rid of the leak. Oh well I hope they fix it soon. NSAutoReleasePool Leaks on allocWithZone
I load a huge-huge image with imageWithContentsOfFile:, so I have to set up an activityIndicator during the process.
Is there any way/any delegate callback I can use to be informed about the end of this loading process?
imageWithContentsOfFile is synchronous.
You could start an activity indicator, load your big image into memory in a background thread and then go back to the main thread and stop the indicator.
- (void)loadBigImage {
[activityIndicator startAnimating];
[self performSelectorInBackground:#selector(loadBigImageInBackground) withObject:nil];
}
- (void)loadBigImageInBackground {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *img = [UIImage imageWithContentsOfFile:#"..."];
[self performSelectorOnMainThread:#selector(bigImageLoaded:) withObject:img waitUntilDone:NO];
[pool release];
}
- (void)bigImageLoaded:(UIImage *)img {
[activityIndicator stopAnimating];
// do stuff
}
Short answer: Nope. sorry!
Long answer :
You could open the file in a background process (an NSOperation?) bit by bit using C style methods i.e. fopen, fread etc) and fire notifications back to the main thread during the load. Then create the image and fire a notification that the image is ready?
If you want to have a delegate & be informed of the progress of the load, you can use an NSURLConnection instead of the synchronous imageWithContentsOfFile.
There's an example of this in the Apple URL Loading System Programming Guide
Your NSURLConnection delegate didReceiveData: method could append the incoming data to an NSData object, then you would use UIImage imageWithData: to create them image once everything's downloaded.
This gives you the most flexibility/control over monitoring the progress of the load; although if all you're trying to do is avoid hanging the UI while the image downloads, simply using imageWithContentsOfFile in a background thread may be easier.
Maybe someone can help me with this strange thing:
If a user clicks on a button, a new UITableView is pushed to the navigation controller. This new view is doing some database querying which takes some time. Therefore I wanted to do the loading in background.
What works WITHOUT leaking memory (but freezes the screen until everything is done):
WorkController *tmp=[[WorkController alloc] initWithStyle:UITableViewStyleGrouped];
self.workController=tmp;
[tmp release];
[self.workController loadList]; // Does the DB Query
[self.workController pushViewController:self.workController animated:YES];
Now I tried to do this:
// Show Wait indicator
....
WorkController *tmp=[[WorkController alloc] initWithStyle:UITableViewStyleGrouped];
self.workController=tmp;
[tmp release];
[self performSelectorInBackground:#selector(getController) withObject:nil];
}
-(void) getController {
[self.workController loadList]; // Does the DB Query
[self.navigationController pushViewController:self.workController animated:YES];
}
This also works but is leaking memory and I don't know why !
Can you help ?
By the way - is it possible for an App to get into AppStore with a small memory leak ? Or will this be checked first of all ?
Thanks in advance !
No, small memory leaks will not (most likely) you application to be rejected from appstore.
In your example as you run your method in separate thread you should create and dispose NSAutoreleasePool object for that thread to handle autoreleased objects. Following changes to getController method should do the trick:
-(void) getController {
NSAutoreleasedPool *pool = [[NSAutoreleasedPool alloc] init];
[self.workController loadList]; // Does the DB Query
[self.navigationController pushViewController:self.workController animated:YES];
[pool release];
}
For more details see Autorelease Pools section in memory management guide. Relevant quote from there:
If you spawn a secondary thread, you
must create your own autorelease pool
as soon as the thread begins
executing; otherwise, you will leak
objects. (See “Autorelease Pools and
Threads” for details.)
Btw, you're calling pushViewController: from a background thread. This is bad.
You should only do things to the UI - like pushing view controllers and changing UI items - from the main thread. If you don't, things break.
See the Cocoa Fundamentals Guide section titled "Are the Cocoa Frameworks Thread Safe?": it says "All UIKit objects should be used on the main thread only."