Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective C Blocks as Async-callbacks & BAD ACCESS

I've got a serious doubt. Suppose the following scenario:

  1. You have a UIViewController onscreen.
  2. The app initiates, say, a backend call using a block as a callback
  3. You use a 'self' surrogate, to prevent retain cycles.
  4. The user hits 'Back', and the UIViewController gets dealloc'ed.
  5. Sooner or later, the callback block gets executed >> BAD ACCESS

Before iOS 4, we dealt with this kind of situation by setting to nil the delegate property of... i don't know, whatever class you were using.

But nowadays... how do you cancel a block??. What if the block was sent to a static method, and you have no way of wiping out that callback reference??.

In that case, should we avoid using the 'self' surrogate?

BTW, by 'self' surrogate, i mean to say:

__block typeof(self) bself = self;

Thanks!!

like image 620
Jorge Leandro Perez Avatar asked Jul 30 '11 19:07

Jorge Leandro Perez


1 Answers

Well, first off: If (and only if) your reason for avoiding the use of self or direct access of ivars inside of a block really are retain-cycles, then you should be in a situation like

client => objectA => blockWithWeakBackReference

(where => means 'has a strong reference to').

In this case, blockWithWeakBackReference should only ever be invoked by objectA, so there is no danger of a BAD ACCESS.

If I understand your question correctly, what you really mean is a different scenario:

  • objectA wants some application-wide service to execute a block on its behalf, if some precondition is met.
  • You avoid using self inside of the block because you want to be able to dispose of objectA before the block is executed.

One example for this might be a shared network-queue that executes a block when the request finished loading for one reason or another.

In that case, I would suggest to simply copy the design of NSNotificationCenter's addObserverForName:object:queue:usingBlock: and make your service implement a pair of methods like -(SomeTokenObjectType)addWorkerBlock:(void(^)(whatever-signature-makes-sense-for-you)) and -(void)cancelWorkerBlockWithToken:(SomeTokenObjectType) in order to enqueue and cancel your callback-blocks.

Then, all objects that use this service can simply have an ivar of type NSMutableSet to store the token for every enqueued block and — in their dealloc — enumerate the remaining tokens, canceling them with the service.

like image 131
danyowdee Avatar answered Nov 17 '22 21:11

danyowdee