In my current project, several view controllers (like vc
) spawn NSOperation objects (like operation
) that are executed on a static NSOperationQueue. While the operation is waiting or running, it will report back to the view controller via delegation (operation.delegate = vc
, assigned not retained).
These operations can take a while though, and in the mean time the app can dealloc the view controller (by popping them of a navigation controller's stack).
So far everything is intentional. The class containing the static NSOperationQueue has a way to get back at the operations, therefore the view controllers do not retain them. They're just alloc/init/autoreleased and put on the queue.
Now this also causes the problem. After the view controller deallocates, any calls to the NSOperation's spirited delegate will cause a bad access violation. From what I understand, it is not possible to check whether an object at a pointer has been deallocated, as stated in this question.
One fix I can think of is retaining the operation and setting the operation.delegate to nil on dealloc. But that'd be my least popular fix, for it would introduce a lot of extra ivars/properties to keep track of.
My question therefore is, are there other ways to work around this problem and if so, could you sketch one here?
Cheers,
EP.
SOLUTION: The approach that worked out best for me was a slight variation to Guiliano's answer:
Implementing every delegate protocol in the queue manager is not feasible (20+ different protocols with 50+ methods), so I kept the direct delegate assignments. What I did change was the class making the assign call. This used to be the class (and delegate) that created the request, but now it is offloaded to the queue manager.
The queue manager, next to assigning the delegate to the operation, also holds a secondary mutable dictionary to keep track of the delegate/operation pairs.
Every delegate instance calls a
[QueueManager invalidateDelegate:self]
method on deallocation, which then looks up the request that belonged to the delegate and nils it. The dictionary operation/delegate pair is then also deleted to allow proper deallocation of the operation.Lastly with KVO observing the
isFinished
property of each operation, the mutable dict is kept clean, to make sure that all operation retain counts actually deallocate after they're finished.
Thanks Guiliano for providing the hint to using KVO for cracking this!