Who owns autorelease objects? - objective-c

In objective-c manual it is written that something like
return [[[SomeClass alloc] init] autorelease];
can be done and then release is not necessary at any point, even not in the function that received this object. Who owns this object then? when will it be released?

The current NSAutoreleasePool does and will take care of the releasing when drained.
IBAction calls get wrapped into an NSAutoreleasePool that gets drained after the call.
For all non-IBAction calls the following would apply:
Say, you have these methods:
- (id)foo {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SomeClass *bar = [self bar]; //bar still exists here
//do other stuff
//bar still exists here
//do other stuff
//bar still exists here
[pool drain]; //bar gets released right here!
//bar has been released
}
- (id)bar {
return [[[SomeClass alloc] init] autorelease]; //bar will still be around after the return
}
Consider another scenario:
- (void)foo {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//do other stuff
[self bar];
//do other stuff
[pool drain]; //the string from blee would be released right here;
}
- (void)bar {
[self baz];
}
- (void)baz {
NSString *string = [self blee];
}
- (id)blee {
return [NSString string]; //autoreleased
}
As you can see the autoreleased string object did not even have to be used in or get returned to the scope in which the pool was created.
NSAutoreleasePools exist on a stack (one per thread) and autoreleased objects get owned by the pool that's topmost at the time of the call to autorelease.
Update:
If you are dealing with a tight loop and want to keep the memory moderately low while not slowing down your loop, consider doing something like this:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (NSUInteger i = 0; i < 1000000000; i++) {
[NSString stringWithString:#"foo"];
if (i % 1000 == 0) {
[pool drain];
pool = [[NSAutoreleasePool alloc] init];
}
}
[pool drain];
However NSAutoreleasePool is highly optimized, so one pool per iteration usually isn't much of a problem.
To fully understand how NSAutoreleasePools work read this excellent article by Mike Ash

Related

autoreleased pool explanation

In my code i am working with audio buffers, when i have a callback function that is being called many times per second. this callback is in a class that handle audio, and not in the main class of the app .
At the start i was getting this warning that is being log many times during callbacks:
Object 0x93cd5e0 of class __NSCFNumber autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool()
Then i was told to put this line in the callback func :
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
then this error disappeared .
But i cant understand how is that possible that i alloc the pool so many times in 1 second- and maybe i have a memory issues.
I saw than that i have to put this at the end :
[pool drain];
so i have this :
OSStatus status;
status = AudioUnitRender(audioUnit,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
&bufferList);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // that line added
//run on evert sample
int16_t *q = (int16_t *)(&bufferList)->mBuffers[0].mData;
for(int i=0; i < inNumberFrames; i++)
{
static int stateMachineSelector=1;
static int sampelsCounter=0;
// CODE TO HANDLE THE SAMPLES ...
}
[pool drain]; // issue here
what exactly i did here?
why is that ?
is that ok from memory aspect ?
thanks a lot .
When starting a Autorelease pool with [[NSAutoreleasePool alloc] init] all further objects receiving a autorelease or where created with the convenience allocator (like NSArray *ary = [NSArray array];, or UIView *view = [[[UIView alloc] init] autorelease]; are in that pool.
So:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *ary = [NSArray array];
[pool release]; // this will also release and dealoc the *ary from memory
If you have a callback running NOT no the main thread, you SHOULD do a new pool. If not, your objects may leek to nirvana. :)
If you process a lot of data with autorelease objects and you'd like to free the memory, then create a pool, process, release the pool.

Xcode Objective C - Help with NSAutoreleaseNoPool error using NSThread

Hey experts, I'm having a little trouble with NSThread. Xcode keeps on giving me "* __NSAutoreleaseNoPool(): Object 0x5694dc0 of class NSCFString autoreleased with no pool in place - just leaking" errors.
I'm correctly declaring the pool with the line
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
then at the end of my loop I use:
[pool release];
Is it because I'm using a delegate method as the performSelectorInBackground?
Thanks stackoverflow.
- (void)preFetch { //process filenames to be downloaded and assign types to each one
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *regions = [NSArray arrayWithObjects: #"dr_national", #"ds_ir", #"conus_FL360", #"FL360_conus", #"dr_nw", #"dr_nc", #"dr_ne", #"dr_sw", #"dr_sc", #"dr_se", #"ds_ir_nw", #"ds_ir_nc", #"ds_ir_ne", #"ds_ir_sw", #"ds_ir_sc", #"ds_ir_se", nil];
NSError* error;
for (NSString *regionDir in regions) {
NSLog(#"region now: %#", regionDir); foo = 0;
NSString *regUrl = [NSString stringWithFormat:#"http://someUrl/%#/index.lst", regionDir ];
NSString* text1 = [NSString stringWithContentsOfURL:[NSURL URLWithString:regUrl ] encoding:NSASCIIStringEncoding error:&error];
NSArray *listItems = [text1 componentsSeparatedByString:#"\n"];
for (int k=0; k<[listItems count]; k++) {
if ([[listItems objectAtIndex:k] length] != 0){
NSString *newpath = [NSString stringWithFormat:#"http://someUrl/%#", [listItems objectAtIndex:k]];
NSLog(#"newpath: %#",newpath);
[self performSelectorInBackground:#selector(moveProgressBar) withObject:nil];
[self fetchImages:newpath:type]; //pass multiple arguments to fetchImages, newpath and type
}
}
}
[pool release];
}
- (void)moveProgressBar{
[delegate increaseAmount];
}
You should just set up an autorelease pool in your method, since that's being called on a different thread.
- (void)moveProgressBar
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[delegate increaseAmount];
[pool drain];
}
Edit
Having said that, looking at the code itself, it seems that you might be trying to update the UI from a background thread? Any code that does that should be executed on the main thread.
If you have a long running process that you want to run which doesn't lock the UI, and keeps the user updated on progress, the typical pattern would be to do the processing itself on a background thread, and periodically update the UI using performSelectorOnMainThread:.

nested NSAutoreleasePool

In one of my applications for iPad I am building up the db remotely using a json string then converted to NSArray to be insert in core data and then I donwload around 600Mb of images on the ipad. All this is created in a background thread causing from the beginning some memory issue.
I get hold of the problem nesting 3 different NSAutoreleasePool in the operation and releasing each of them at a convenient point. I got no error, nor leak, nor warning. I was just wondering if it is a good way of doing it or I just miss something.
Here a schematic example (the real code is quite long):
- (void)main{
#try {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // first pool
[managedOC lock];
NSArray *results = [self loadEntitiesWithGroupName:#"Project" andName:#"projects"];
NSAutoreleasePool *prjPool; // second pool
for (NSDictionary *thisResult in results) {
prjPool = [[NSAutoreleasePool alloc] init];
Project *prj = [[Project alloc] initWithEntity:[NSEntityDescription entityForName:#"Project" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext:self.managedOC];
prj.name = [thisResult objectForKey:#"name"];
[prj saveThumbnail:[thisResult objectForKey:#"thumbnail"]];
//Slides. Those are the images that take so mutch space.
NSArray *slides = [thisResult objectForKey:#"slides"];
NSAutoreleasePool *slidePool; // third pool
if(slides != kCFNull){
slidePool = [[NSAutoreleasePool alloc] init];
for(NSDictionary *slide in slides){
Slide *thisSlide = [[Slide alloc] initWithEntity:[NSEntityDescription entityForName:#"Slide" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext: self.managedOC];
thisSlide.path = prj.path;
[thisSlide saveFile:[slide objectForKey:#"file"]];
[prj addSlidesObject:thisSlide];
[thisSlide release];
[slidePool drain];
}
}
[prj release];
[result release];
[prjPool drain];
}
[self.managedOC unlock];
[totResult release];
[pool drain];
}
#catch (NSException * e) {
}
I'm surprised your code doesn't crash. -drain behaves the same as -release in the reference counted environment, so the following over releases the pool
slidePool = [[NSAutoreleasePool alloc] init]; // this is in the wrong place
for(NSDictionary *slide in slides){
Slide *thisSlide = [[Slide alloc] initWithEntity:[NSEntityDescription entityForName:#"Slide" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext: self.managedOC];
thisSlide.path = prj.path;
[thisSlide saveFile:[slide objectForKey:#"file"]];
[prj addSlidesObject:thisSlide];
[thisSlide release];
[slidePool drain];
}
Unless there is only one object in the slides collection. You need this:
for(NSDictionary *slide in slides){
slidePool = [[NSAutoreleasePool alloc] init]; // this is in the right place
Slide *thisSlide = [[Slide alloc] initWithEntity:[NSEntityDescription entityForName:#"Slide" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext: self.managedOC];
thisSlide.path = prj.path;
[thisSlide saveFile:[slide objectForKey:#"file"]];
[prj addSlidesObject:thisSlide];
[thisSlide release];
[slidePool drain];
}
Other than that, you have the right general idea.
You should drain your outermost pool in the finally block of your exception handler so that it is not skipped if an exception is raised i.e. you should do this:
- (void)main{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // first pool
#try {
// Do al your stuff
}
#catch (NSException * e) {
}
#finally
{
[pool drain];
}
}

Why am I getting *** _NSAutoreleaseNoPool(): Object 0x97480b0 of class NSCFDictionary autoreleased with no pool in place - just leaking

I have noted several other threads on this topic and have tried wrapping my threaded code with:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[pool release];
but the errors still come.
I am using a static method to instantiate a dictionary of words.
Here is some code:
-(id)init
[NSThread detachNewThreadSelector:#selector(loadDictionary:) toTarget:[IntroScreen class] withObject:nil];
[NSThread setThreadPriority:1.0];
return self;
}
+(void)loadDictionary:(id)param
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"click.wav"];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"pop.wav"];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"dink.wav"];
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:#"musicloop.wav"];
[WordDictionary configDictionary];
[pool release];
}
+(void)configDictionary
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Serializer * mySerializer = [[Serializer alloc] init];
[WordDictionary setDictionary:[mySerializer readApplicationPlist:#"x"]];
NSString * string;
NSString *filePath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"x.txt"];
NSString *info = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayOfLines = [info componentsSeparatedByString:#"\r\n"];
[WordDictionary setDictionary:[[NSMutableDictionary alloc] init]];
[NSMutableDictionary dictionaryWithContentsOfFile:filePath];
int len = [arrayOfLines count];
for(int i = 0; i < len; i++)
{
string = [arrayOfLines objectAtIndex:i];
NSString * blankString = [NSString stringWithString:#""];
[[WordDictionary dictionary] setObject:blankString forKey:string];
double calc = ((double)i / (double)len) * 100.0;
[WordDictionary setProgress:(int)calc];
}
[mySerializer writeApplicationPlist:[WordDictionary dictionary] toFile:#"s"];
[WordDictionary setProgress:100];
[pool release];
}
Is there something I should know about using static class methods with new selector threads?
Thank you for your help
First, there are no static methods in Objective-C. There are class methods.
Secondly, your code shows both methods wrapped in autorelease pools. The warning must be coming from somewhere else.
Finally, your code leaks like a sieve. You aren't following the memory management rules. And there are some nonsense statements in there.
Specifically:
[WordDictionary setDictionary:[[NSMutableDictionary alloc] init]];
Unless +setDictionary: is breaking the memory management rules, the above leaks.
This statement [NSMutableDictionary dictionaryWithContentsOfFile:filePath]; effectively does nothing unless you do something with the return value.
Also, mySerializer is leaking.
Try running the analyzer over your code and fixing the problem. You should also read this and this.
Ah the [NSMutableDictionary dictionaryWithContentsOfFile:filePath]; was part of an experiment I was attempting to make the dictionary access faster. I should have removed it from this example.
I have just read the memory management rules, and understand that
[WordDictionary setDictionary:[[NSMutableDictionary alloc] init]]; appears to be poorly planned instantiation because I have no way to release it from within configDictionary as the reference is lost. But actually I don't ever want to release it, it lives for the entire lifetime of my application. Probably bad practice just the same.
mySerializer should definitely be released at the bottom.
I was just wondering if class methods had any special rules regarding autorelease pools and memory.
I will look over the documents you sent me and try to figure out the Analyzer, thank you for your help.

Do multithreading and autorelease pools work together in Cocoa?

I would like to send an object back to the main thread from worker thread. However do auto-release pools work between threads? Is there anything wrong with the following code:
-(void)mainThreadReceiveResult:(id)response
{
[response retain];
/* Do some stuff with response */
[response release];
}
-(void)workerThreadDoWork
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
response * response = [[[response alloc] init] autorelease];
response->someData = [self getSomeData];
[delegate performSelectorOnMainThread:#selector(receiveResult:) withObject:response waitUntilDone:NO];
[pool release];
}
Seems to work fine. However is it possible that the worker thread could reach [pool release] before the main thread is able to retain it?
Your code shouldn't crash: performSelectorOnMainThread: retains its arguments until after the selector finishes, so your retain/release pair is superfluous.
See the documentation:
This method retains the receiver and the arg parameter until after the selector is performed.
Also: you should probably [pool drain] instead of [pool release].
This may answer your question.
Here's what he did to solve the problem. The explanation is given in that link.
- (void)runSomethingThatWillFail:(NSError **)error {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *directoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:#"/BOGUS" error:error];
[*error retain];
[pool release];
[*error autorelease];
}