3

My main program spawns a thread, which executes the following:

// alloc autorelease pool somewhere before
NSArray *blah = [NSArray arrayWithObject: @"moo"];
[self performSelectorOnMainThread: @selector(boonk:) withObject: blah
      waitUntilDone: NO];
// release autorelease pool somewhere after

Now, this seems buggy to me because the autorelease pool could be released before the selector boonk: is finished executing, which would cause a crash.

So, my natural next move would be:

// alloc autorelease pool somewhere before
NSArray *blah = [[NSArray alloc] initWithObject: @"moo"];
[self performSelectorOnMainThread: @selector(boonk:) withObject: blah
      waitUntilDone: NO];
// release autorelease pool somewhere after


- (void)boonk: (id)data
{
   // do something with data
   [data release];   // release the ref count the thread added
}

This definitely is bug-free, but .... seems unnatural. Is there an objective-c ref counting convention or protocol to handle this situation (cross thread NO-wait posting), or is the second solution above the way it's done?

bbum
  • 162,346
  • 23
  • 271
  • 359
MarcWan
  • 2,943
  • 3
  • 28
  • 41

2 Answers2

9

Actually, performSelectorOnMainThread retains its arguments until after the selector is performed, so there's no need to do it.

Adam Woś
  • 2,493
  • 20
  • 21
  • Well, I'll be danged, that's it. They hid that in a tiny little note at the end of the method description. Fantastic, thanks! – MarcWan Jan 11 '10 at 11:13
  • Well, I only remembered the *until selector is performed*, not *until after* :) – Adam Woś Jan 11 '10 at 11:15
  • Hmmm, wouldn't the argument (NSArray blah) be released *after* performing the selector? The whole purpose of retaining the argument by the framework is to free *you* from retaining and releasing it and to ensure you don't forget to retain it causing a crash. Autorelease pools are out of scope here because the coder does not retain the argument, but the framework both retains and releases it when necessary. – Costique Jan 11 '10 at 11:19
  • @Costique, please see the revised answer - I did not remember the *after* part, hence my previous version of the answer :) – Adam Woś Jan 11 '10 at 11:27
  • @AdamWoś It does not seem to be mentioned in the current reference guide of the function .. ? I am doing manual memory managment, so has apple put the manual memory doc to junk with the arrival of ARC ? – Ahmed Feb 21 '13 at 15:10
3

The rule is simple; to pass an object from thread A to thread B, there must exist a hard retain. Now, as documented, -performSelectorOnMainThread: (and variants) do retain the objects until the method is finished executing, regardless of synchronous or asynchronous invocation.

However, it is generally sensible to maintain a retain-on-sending-thread-that-is-released-on-receiving-thread motif. It is explicit in intention and will support future refactorings, potentially to other models that do not do the automatic retain/release.

And, to repeat because it is important, autorelease pools cannot be used to preserve objects across threads.

bbum
  • 162,346
  • 23
  • 271
  • 359