Reputation: 18922
I was trying to create a callback that retries the method after a delay on failure. I'm hitting this warning:
"Capturing failure block strongly in this block is likely to lead to a retain cycle."
typedef void (^MyCallbackBlock)(NSObject *);
...
__block MyObject *blockSelf = self;
__block MyCallbackBlock successBlock = ^(NSObject *someObject)
{
// To be completed
};
__block MyCallbackBlock failureBlock = ^(NSObject *someObject)
{
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[blockSelf doSomething:someObject onSuccess:successBlock onFailure:failureBlock]; // <-- Warning is here
});
};
[blockSelf doSomething:someObject onSuccess:successBlock onFailure:failureBlock];
...
- (void)doSomething:(NSObject *)someObject
onSuccess:(MyCallbackBlock)successBlock
onFailure:(MyCallbackBlock)failureBlock;
The question: How can I make this work properly?
(I've been reading through other SO questions -- haven't found a match yet, though wouldn't be surprised if one is out there.)
Upvotes: 1
Views: 196
Reputation: 18922
Adding __unsafe_unretained
worked, as in:
__unsafe_unretained __block MyCallbackBlock successBlock = ^(NSObject *someObject)
{
// To be completed
};
While it seemed possible that __weak
could work, in practice it caused my application to crash. It's not 100% clear that this answer explains the reason, but I'm imagining it's something along those lines.
Upvotes: 0
Reputation: 122439
Yes, the block needs to capture itself (as well as self
) as a weak reference.
If you're using ARC*, it should be like this:
MyObject *__weak blockSelf = self;
__block __weak MyCallbackBlock weakSuccessBlock;
MyCallbackBlock successBlock = weakSuccessBlock = ^(NSObject *someObject)
{
// To be completed
};
__block __weak MyCallbackBlock weakFailureBlock;
MyCallbackBlock failureBlock = weakFailureBlock = ^(NSObject *someObject)
{
MyCallbackBlock strongSuccessBlock = weakSuccessBlock;
MyCallbackBlock strongFailureBlock = weakFailureBlock;
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[blockSelf doSomething:someObject onSuccess:strongSuccessBlock onFailure:strongFailureBlock];
});
};
If you're not using ARC, replace the __block __weak
and __weak
above with just __block
.
Upvotes: 2