11

I have a task that takes a rather long time and should run in the background. According to the documentation, this can be done using an NSOperationQueue. However, I do not want to keep a class-global copy of the NSOperationQueue since I really only use it for that one task. Hence, I just set it to autorelease and hope that it won't get released before the task is done. It works.
like this:

NSInvocationOperation *theTask = [NSInvocationOperation alloc];
theTask = [theTask initWithTarget:self
                         selector:@selector(doTask:)
                           object:nil];
NSOperationQueue *operationQueue = [[NSOperationQueue new] autorelease];
[operationQueue addOperation:theTask];
[theTask release];

I am kind of worried, though. Is this guaranteed to work? Or might operationQueue get deallocated at some point and take theTask with it?

bastibe
  • 16,551
  • 28
  • 95
  • 126
  • Not sure about the answer, but `[NSOperationQueue new]` returns an autoreleased object, so `[[NSOperationQueue new] autorelease]` will make you release twice on the same queue, and should make you crash. Also, always and ever do `[[Class alloc] init...]` nested. Don't separate `alloc` and `init` ever. You'll save yourself some headaches. – Johan Kool Mar 23 '10 at 17:51
  • 15
    [NSObject new] is equivalent to [[NSObject alloc] init], so not autoreleased... – dstnbrkr Mar 23 '10 at 18:01
  • Not the answer you are looking for, but since you only want it for one task is `[self performSelectorInBackground:@selector(doTask:) withObject:nil]` an option. Or must it be an NSOperation? – Brandon Bodnar Mar 23 '10 at 18:58
  • @Brandon_Bodnar: that sounds great, but for some reason, it makes my application choke. – bastibe Mar 23 '10 at 20:27
  • 1
    What about not autoreleasing the queue, but instead add another task to the end of the queue, which releases it? – Nick Moore Mar 24 '10 at 15:31
  • @invariant that is an interesting idea! – bastibe Mar 24 '10 at 15:57

4 Answers4

5

There's nothing in the documentation to say what happens when the NSOperationQueue is released. It would be safest to assume there's no guarantee that theTask will get executed.

Nick Moore
  • 15,547
  • 6
  • 61
  • 83
1

I would have guessed that an NSOperationQueue releases its tasks when it's released, but I've noticed that the tasks do complete and dealloc even if I release the queue immediately after adding the task. That said, I don't think I'd rely on that behavior - there's more to gain by storing the NSOperationQueue in an instance variable (and releasing it in dealloc). An instance variable will give you a way to call other methods on the queue (cancelAllOperations, setSuspended, etc).

dstnbrkr
  • 4,305
  • 22
  • 23
  • there is no further interaction I wish to do. It wouldn't even be much of a problem if the task did not complete at all (a background image would look slightly fuzzy is what would happen). – bastibe Mar 23 '10 at 18:32
  • 1
    probably not dangerous to release the queue in that case, with the caveat that since there isn't any documentation, there's no guarantee that it won't work differently in later SDK releases. I'm guessing NSOperationQueue bumps it's retain count until all tasks complete. – dstnbrkr Mar 24 '10 at 00:26
1

Can't you use the [NSOperation mainQueue] object so that you don't need to worry about autoreleasing it? If you only need to add one task that seems to make the most sense to me.

http://developer.apple.com/mac/library/documentation/Cocoa/Reference/NSOperationQueue_class/Reference/Reference.html#//apple_ref/doc/uid/TP40004592-RH2-SW21

Steven Behnke
  • 3,336
  • 3
  • 26
  • 34
  • 1
    Unless they want that task to run in parallel to the main thread which is handling GUI events. `mainQueue` runs in serial. – Brandon Bodnar Mar 23 '10 at 18:55
1

There's no guarantee that it's safe to release an NSOperationQueue while it's still working. I suspect it probably is safe and this guarantee will probably be added someday, but it isn't there now. However, the equivalent Grand Central Dispatch API does guarantee that you can safely release its queues when you're done using them and it will keep them around as long as it needs them. So if you're on a platform with GCD, you can use that to be sure it won't blow up in the meantime.

Alternatively, you could create a wrapper class that checks if a queue is finished and releases both the queue and itself when the queue is finished.

Chuck
  • 234,037
  • 30
  • 302
  • 389