I have a block retain cycle question,
suppose I have the following 3 methods, all in one class.
- (void)foo1WithBlock:(void (^)(BOOL success))completion
// do something...
completion(YES)
}
- (void)foo2 {
// do something...
}
- (void)foo3 {
[self foo1WithBlock:^(BOOL success) {
[self foo2];
}];
}
Will foo3 create a retain cycle?
No, there is no retain cycle.
However, self will be captured. This means, self will be imported into the lexical scope of the compound statement (the statements executed by the block). This involves making a copy of the "outside" variable self which creates the block's variable self.
A block can be copied and released. A block_copy operation will "move" the captured variables onto the heap. They exists there until the block gets destroyed via block_release operation. The compiler/runtime provides internal functions to copy and release a block and performs them when required. For example, if the block is executed asynchronously via dispatch_async() the block will have to be copied first, and later when the block is finished, released again. These block_copy and block_release operations are inserted by the compiler and executed by the runtime, so don't worry.
If the block will be copied, as an effect self will be retained, and released again when the block gets released - which happens when the block has been finished.
In effect, this guarantees that self within the block and during the life-time of the block is valid (that is, it won't get deallocated), whether it is called synchronously or asynchronously. When the block has been executed asynchronously, the block has been copied, and thus self has been retained. And self will be only released again until after the block finishes. This also means, that the block "will" extend the life time of self until after the block finishes.
No, there will no retain cycle..as you are not calling each other method here.
- (void)foo3 {
[self foo1WithBlock:^(BOOL success) {
[self foo2];
}];
}
In this case, if you don't understand the lifetime of the block you are passing to foo1WithBlock: it is probably a good idea to use this idiom to prevent a the block from inappropriately extending the lifetime of self.
- (void)foo3 {
__weak ParentType *wself = self; //create a weak reference (weak automatically gets set to nil on dealloc)
[self foo1WithBlock:^(BOOL success) {
ParentType *self = wself; //create a local strong reference for the life of the block.
[self foo2];
}];
}
if you are using cocoapods libextobjc has a EXTScope which provides helper macros for this:
- (void)foo3 {
#weakify(self);
[self foo1WithBlock:^(BOOL success) {
#strongify(self);
[self foo2];
}];
}
Related
I am experiencing an EXC_BAD_ACCESS error inside my app within a block that, as of my understanding, should actually capture everything involved in this, making it impossible that it is released inside the block. (ARC is enabled)
Here is my code:
- (void)_perform_async_onqueue:(void (^)(void))task {
dispatch_async(self.workerQueue, task);
}
- (void)cancel {
[self _perform_async_onqueue:^{
// operation is strongly retained by self.
// operation is also retained by an operation queue.
// within `cancel` the operation is released from the operation queue
[self.operation cancel];
}
}];
This crashes inside [self.operation cancel]. self.operation is a subclass of NSOperation. The operation's cancel method in detail:
- (void)cancel {
[self willChangeValueForKey:#"isCancelled"];
_cancelled = YES;
[self didChangeValueForKey:#"isCancelled"];
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
_finished = YES;
_executing = NO;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"]; // CRASH (debugger lists `self` [= the operation] as `nil` in this line
}
As of my understanding, the first self should be retained inside the dispatched block. As self has a strong reference to operation, this should also be in memory until the end of the block execution. How can this lead to a EXC_BAD_ACCESS crash?
EDIT :
Don't implement cancel method in your NSOperation subclass. Just call :
[self.operation cancel];
A good tuto here
Methods don't have strong references to self. If self is deallocated while a method is being called, you are on your own. (That's why you get a warning if you call a method on a weak object, because the object might go away while the method is running).
You can assign SomeClass* myself = self; and that will keep self alive until the end of the method.
You can also implement your own dealloc (which just calls [super dealloc] automatically) and set a breakpoint to find out when exactly self is deallocated, to understand things better.
I've found the issue:
It turns out that the described behaviour is working totally fine. The issue is that the NSOperation that is used here is a custom, asynchronous operation that has implemented cancel in the wrong way: If you cancel an operation before it has been started by the NSOperationQueue the operation queue then overreleases the operation. This is the reason for the operation being deallocated even if there is still a strong reference that should hold it.
I'll go file a rdar for that.
In MyViewController in viewDidLoad I have only one call:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.isNeedToExecute = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self doSomeSimpleThings];
});
}
-(void)doSomeSimpleThings {
if (!self.isNeedToExecute) {
return;
}
// do some simple actions
}
- (void)dealloc {
self.isNeedToExecute = NO;
}
After that in code I pop this view controller, so without dispatch_after the dealloc would be executed for sure.
The questions:
1) will the dealloc method be called in this case (when we have dispatch_after, that should be executed in 20 seconds)?
2) will this method [self doSomeSimpleThings]; be executed after dealloc?
Edit:
I tried it before posting this question, and dealloc wasn't called and thought that it was strange, that's why I asked this question here.
Your current code creates a retain cycle because you reference self inside the block. You can break the cycle by using a weak reference to self. This way you also don't need the isNeedToExecute flag:
__weak id blockSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[blockSelf doSomeSimpleThings];
});
After deallocation of your view controller blockSelf is nil and doSomeSimpleThings won't be executed.
1) will the dealloc method be called in this case (when we have
dispatch_after, that should be executed in 20 seconds)?
dealloc will be called after there are no strong references to the object anymore. The block holds a strong reference to the object. dispatch_after keeps the block until after it runs. So after 20 seconds, after the block runs, there will be no more strong references, and the object can be deallocated (dealloc called).
2) will this method [self doSomeSimpleThings]; be executed after
dealloc?
This is backwards. In fact, when dealloc is called is determined by when the block (containing [self doSomeSimpleThings]) runs. So the answer is no, kind of by definition, because dealloc cannot run until it is no longer possible to run [self doSomeSimpleThings] in this case.
Check the definition of dispatch_after method. Parameters are defined as
queue:- The queue on which to submit the block. The queue is retained by the system until the block has run to completion. This parameter cannot be NULL.
block: - <......>This function perform a Block_copy and Block_release on behalf of the caller.
So basically your controller object will be retained by this queue even if you have poped it and method doSomeSimpleThings will be called and then dealloc.
I have written a recursive block following these guidelines:
NSMutableArray *groups = [NSMutableArray arrayWithArray:#[#"group1", #"group2", #"group3", #"group4"];
__block CommunicationCompletionHandler completion = [^{
[groups removeObjectAtIndex:0];
if ([groups count] > 0) {
// This will send some information to the network, and calls the completion handler when it receives a response
[mySocket saveGroup:groups[0] completion:completion];
}
} copy]; // Removing copy here doesn't work either
[mySocket saveGroup:groups[0] completion:completion];
In the saveGroup:completion: method, I add the completion handler to an array:
self.completionHandlers[SaveGroupCompletionHandlerKey] = [completion copy];
And when I receive a response, I call the following method (key is in this case SaveGroupCompletionHandlerKey):
- (void)performCompletionHandlerForKey:(NSString *)key {
if (self.completionHandlers[key]) {
((CommunicationCompletionHandler)self.completionHandlers[key])();
[self.completionHandlers removeObjectForKey:key];
}
}
The problem is that the completion handler only gets called once. The removeObjectForKey: line makes the block deallocate. If I uncomment that line, everything works fine. I'm not sure how the array has the last reference to this block, since I add a copy (which I believe is being optimized to a retain).
For clarity, the flow of the app is:
Send data for first group over network
Receive response
Call completion handler
In the completion handler, send data for next group (this is the recursive part).
Anybody here who can point out what I'm doing wrong?
In -performCompletionHandlerForKey: you remove the completion handler from your dictionary after executing the block, which means that the handler will always be removed from the dictionary after one run.
Instead, store the block in a temporary variable and remove it from the dictionary before executing the block.
By the way, the advice to remove the weak reference is wrong. As your code is written now, your block will never be deallocated. The typical block recursion pattern is this:
__weak __block MyBlock weakHandler;
MyBlock handler = ^ {
if (foo) {
MyBlock strongHandler = weakHandler;
[bar asyncOperationWithCompletion:strongHandler];
}
};
weakHandler = handler;
[bar asyncOperationWithCompletion:handler];
A popular way to avoid retain retain cycles is to create a weak reference to the object before defining the block, then create a strong reference inside the block and set it to that weak reference. This method is frequently used to avoid strongly capturing self inside of blocks:
- (void)someMethod {
__weak MyType *weakSelf = self;
[self someMethodWithABlockArg:^{
MyType *strongSelf = weakSelf;
[strongSelf someOtherMethod];
}];
}
The strong reference created inside the block prevents the object from being deallocated while the block is running. You can, of course, do the same with any object type.
Edit2: Looks like [someBlock copy] is indeed fine. Have you tried running Analyze on the code? It may be that completion is not yet initialized when it is referred to inside of the block.
I'm trying to figure out if I do this right:
If I have one block, I'll do this:
__weak MyClass *weakSelf = self;
[self performBlock:^{ //<< Should I use self, or weakSelf here?
[weakSelf doSomething];
} afterDelay:delay];
But what happens if there's a block in a block? Would this be correct?
__weak MyClass *weakSelf = self;
[self performBlock:^{
[weakSelf doSomething];
[self performBlock:^{
[weakSelf doSomething];
} afterDelay:1.0f];
} afterDelay:delay];
Also, in the function below, do I need to use [block copy]?
- (void)performBlock:(void (^)(void))block afterDelay:(float)delay
{
if (block)
{
if (delay > 0)
{
[self performSelector:#selector(executeBlockAfterDelay:) withObject:[block copy] afterDelay:delay];
}
else
{
[self executeBlockAfterDelay:[block copy]];
}
}
}
- (void)executeBlockAfterDelay:(void(^)(void))block
{
if (block)
block();
}
In this case (below) use just strong self, because the block is copied just for those few seconds. And usually if you want the self to perform block, you want to it to stay alive until that time, so strong reference is perfectly okay.
[self performBlock:^{
[self doSomething]; // strong is OK
} afterDelay:delay];
Block inside a block? In your case those two block are just delayed one-shot blocks, so the same as above, use strong. But there are differences between blocks. If you store the block for longer time, maybe for multiple invocations you should avoid retain-cycles.
Example:
self.callback = ^{
[self doSomething]; // should use weakSelf
};
This may cause retain-cycle. In fact it depends on how the block is used. We see that the block is stored (copied) in property for later use. However, you can prevent the retain-cycles by nullifying block that will not be used any more. In this case:
self.callback(); //invoke
self.callback = nil; //release
When using ARC, you don't have to copy blocks yourself. There were bugs in early versions after blocks were added, but now the compiler under ARC knows when to copy blocks. It is clever enough to copy it in this case:
[self performSelector:#selector(executeBlockAfterDelay:) withObject:block afterDelay:delay];
Rather than implementing -performBlock:afterDelay:, just use dipatch_after(). Among other things, that's not a message delivered to an object, so there's no question of what receiver to target it at.
Actually, there's no memory management issue here at all. One typically only needs to do a "weak self" approach when an object retains a block and the block (perhaps implicitly) retains that same object. However, the object is not retaining the block. It is being retained by the framework until the -performSelector:withObject:afterDelay: fires, but that's not a retain cycle.
If there were a retain cycle, then you should not reference self in the blocks. So, your nested case is wrong in invoking a message on self rather than weakSelf.
Finally, yes, you do need [block copy] whenever you are keeping a block after execution leaves the scope of its declaration or if you pass it to non-block-specific API that does. That is, you don't need to copy a block when you pass it to, say, dispatch_async() because that's a block-aware API that knows to make its own copy as necessary. But -performSelector:withObject:afterDelay: is not block-aware. It just treats its argument as a generic object and retains it. So, you do have to copy the block when passing it to that.
One the most important thing to understand about blocks is that they capture a piece of code (including values) in an abstract entity that can be manipulated as an atomic object (keep it somewhere, pass it, copy, etc...). Actually it is implemented in a way that guarantee that by default your block will remain valid and executable safely later.
Then capturing and retaining the required dependencies inside the block is necessary.
Unfortunately, in some cases (quite often actually) the block is retained by the instance that creates it and it retains itself that instance. This is called a retain loop and makes your object and your block impossible to dealloc unless you break one of the retaining relation yourself. This can happen if you reference your block with an instance variable for example and you don't nillify it manually.
This is probably the main issue with blocks especially because sometime, you don't know that your block retains your self instance (NSAssert within your block for example). Then:
If you execute your block immediately and release it (use your block
with dispatch release it after execution) there is no risk since you
are sure your object referenced by self still exist.
But if the execution is delayed it is important to retain your object within your block. But in that case your object should not retain your block to avoid a retain loop (A retains B and B retains A). If you define and optionally reference your block in the private scope of method it is perfect.
About copy. Yes it can be safer to use copy if your block in passed as a method argument to be sure you have a clean exclusive block in this scope with a +1 retainCount. But maybe ARC already do it for you. Not sure about that. For example it performWithSelector seems to do it for free, then copy is not dangerous. Just a useless. Sometime the compiler can optimise that by removing it but it has to be checked.
I usually do this:
__unsafe_unretained __block id blockSelf = self;
and then use it in my blocks no issues.
So in your case:
__unsafe_unretained __block MyClass *blockSelf = self;
[self performBlock:^{
[weakSelf doSomething];
[self performBlock:^{
[weakSelf doSomething];
} afterDelay:1.0f];
} afterDelay:delay];
Also to make your life a tad easier - make a utilities class and put this in the header
void RunAfterDelay(NSTimeInterval delayInSeconds, dispatch_block_t block);
and then this in the .m file
void RunAfterDelay(NSTimeInterval delayInSeconds, dispatch_block_t block)
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC), dispatch_get_main_queue(), block);
}
Import the utilities into your prefix and you can go:
__unsafe_unretained __block MyClass *blockSelf = self;
RunAfterDelay(1.0f,^{
[blockSelf doSomething];
RunAfterDelay(delay,^{
[blockSelf doSomething];
})
});
I find it a bit nicer to read than the verbose default ones.
Hope this helps :)
Assuming an example block as shown below executed.
[testBlock testPerformWithBlock:^(BOOL finished) {
if (finished) {
self.textField.text = #"Finished";
NSLog(#"Edited to add an textfield update inside block");
}
}];
What will happen if I pop the view controller that contains the object testBlock before the block returns the value of BOOL. Will the objects get deallocated properly?
Everything inside a block is retained until the block is released from memory. If the object testBlock is still executing testPerformWithBlock and the block is still alive, then everything inside the block is retained.
You are only doing an NSLog in there, so nothing will change.
However, if you do this:
if (finished) {
[self doSomething];
}
self is being used, and it will be retained, so take some caution if you are storing the blocks in some ivar somewhere
I don't understand what you are asking. There is no problem with memory management in your example. If you did not explicitly retain something, you do not need to explicitly release it.
You will get warning that strongly capturing self inside block will lead to retain cycle it will not crash but its not proper you need to do as they say strong weak dance.You can do this.
__weak typeof(self)ref=self;
^(<your bock>){
__strong typeof(ref)strongSelf=ref;
if(strongSelf)//or if(!strongSelf)return;
{
[strongSelf-><variable> methodCall];
}
};
There will be no deallocated error.
Though the retainCount of "testBlock" will not change after the invocation, the block will not be released before it runs to the end.
The result is that program will run perfectly no matters "testBlock" dealloc or not.
The sample codes following:
- (void)lazyFetchingImage:(void (^)(void))finishBlock {
[[NSOperationQueue mainQueue] addOperationWithBlock:finishBlock];
}
MainVCAppDelegate *dd = [MainVCAppDelegate new];
NSLog(#"count==%i",[dd retainCount]);
[dd lazyFetchingImage:^{
NSLog(#"22");
}];
NSLog(#"count==%i",[dd retainCount]);
[dd release];
The out put should be :
count==1
count==1
22