问题
I've got a serious doubt. Suppose the following scenario:
- You have a
UIViewControlleronscreen. - The app initiates, say, a backend call using a block as a callback
- You use a 'self' surrogate, to prevent retain cycles.
- The user hits 'Back', and the
UIViewControllergets dealloc'ed. - 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!!
回答1:
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:
objectAwants some application-wide service to execute a block on its behalf, if some precondition is met.- You avoid using
selfinside of the block because you want to be able to dispose ofobjectAbefore 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.
回答2:
"to prevent retain cycles."
But do you really have a retain cycle to prevent? Think about this. The block retains self (your view controller). The backend call retains the block. But where does self retain the block?
来源:https://stackoverflow.com/questions/6885514/objective-c-blocks-as-async-callbacks-bad-access