问题
I've got a serious doubt. Suppose the following scenario:
- You have a
UIViewController
onscreen. - 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
UIViewController
gets 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:
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 ofobjectA
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.
回答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