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
Related
I just finished debugging a very nasty UIViewController leak, such that the UIViewController was not dealloc'd even after calling dismissViewControllerAnimated.
I tracked down the issue to the following block of code:
self.dataSource.doNotAllowUpdates = YES;
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadItemsAtIndexPaths:#[indexPath]];
} completion:^(BOOL finished) {
self.dataSource.doNotAllowUpdates = NO;
}];
Basically, if I make a call to performBatchUpdates and then immediately call dismissViewControllerAnimated, the UIViewController gets leaked and the dealloc method of that UIViewController never gets called. The UIViewController hangs around forever.
Can someone explain this behavior? I assume performBatchUpdates runs over some time interval, say, 500 ms, so I would assume that after said interval, it would call these methods and then trigger the dealloc.
The fix appears to be this:
self.dataSource.doNotAllowUpdates = YES;
__weak __typeof(self)weakSelf = self;
[self.collectionView performBatchUpdates:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf) {
[strongSelf.collectionView reloadItemsAtIndexPaths:#[indexPath]];
}
} completion:^(BOOL finished) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf) {
strongSelf.dataSource.doNotAllowUpdates = NO;
}
}];
Note that the BOOL member variable, doNotAllowUpdates, is a variable I added that prevents any kind of dataSource / collectionView updates while a call to performBatchUpdates is running.
I searched around for discussion online about whether or not we should use the weakSelf/strongSelf pattern in performBatchUpdates, but did not find anything specifically on this question.
I am happy that I was able to get to the bottom of this bug, but I would love a smarter iOS developer to explain to me this behavior I am seeing.
This seems like a bug with UICollectionView. API users should not expect single-run block parameters to be retained beyond the execution of the task, so preventing reference cycles should not be an issue.
UICollectionView should be clearing up any references to blocks once it has finished the batch update process, or if the batch update process is interrupted (for example, by the collection view being removed from the screen).
You've seen for yourself that the completion block is called even if the collection view is taken off-screen during the update process, so the collection view should then be nilling out any reference it has to that completion block - it will never be called again, regardless of the current state of the collection view.
As you figured out, when weak is not used a retain cycle is created.
The retain cycle is caused by self having a strong reference to collectionView and collectionView now has a strong reference to self.
One must always assume that self could have been deallocated before an asynchronous block is executed. To handle this safely two things must be done:
Always use a weak reference to self (or the ivar itself)
Always confirm weakSelf exists before passing it as a nunnull
param
UPDATE:
Putting a little bit of logging around performBatchUpdates confirms a lot:
- (void)logPerformBatchUpdates {
[self.collectionView performBatchUpdates:^{
NSLog(#"starting reload");
[self.collectionView reloadItemsAtIndexPaths:[self.collectionView indexPathsForVisibleItems]];
NSLog(#"finishing reload");
} completion:^(BOOL finished) {
NSLog(#"completed");
}];
NSLog(#"exiting");
}
prints:
starting reload
finishing reload
exiting
completed
This shows that the completion block is fired AFTER leaving the current scope, which means it is dispatched asynchronously back to the main thread.
You mention that you immediately dismiss the view controller after doing the batch update. I think this is the root of your issue:
After some testing, the only way I was able recreate the memory leak was by dispatching the work before dismissing. It's a long shot, but does your code look like this by chance?:
- (void)breakIt {
// dispatch causes the view controller to get dismissed before the enclosed block is executed
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadItemsAtIndexPaths:[self.collectionView indexPathsForVisibleItems]];
} completion:^(BOOL finished) {
NSLog(#"completed: %#", self);
}];
});
[self.presentationController.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}
The code above leads to dealloc not being called on the view controller.
If you take your existing code and simply dispatch (or performSelector:after:) the dismissViewController call you will likely fix the issue as well.
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];
}];
}
I have following code snippet:
-(void) doSomething
{
__block NSMutableArray *objArray = [[NSMutableArray alloc] initWithCapacity:0];
[self performOperationWithBlock:^(void)
{
//adding objects to objArray
.
.
//operation with objArray finished
// 1. should objArray be released here?
}];
//2. should objArray be released here?
}
Should I autorelease the objArray?
If it's an asynchronous call, it would make sense to create the NSMutableArray inside the actual block:
[self performOperationWithBlock:^(void)
{
NSMutableArray *objArray = [[NSMutableArray alloc] initWithCapacity:0];
//adding objects to objArray
.
.
//operation with objArray finished
// 1. should objArray be released here?
}];
As you won't be needing it after the block (it only makes sense for the duration of the async operation), so in the end release it after you have used it. Or, you can simply:
NSMutableArray *objArray = [NSMutableArray array];
And in this case you don't need to release it.
If it's a sync call, you should release it after the block.
Note: I am assuming you are populating the NSMutableArray before being used on the block, which means it makes sense to be created before the block starts.
Async approach:
-(void) doSomething
{
// Remove the `__block` qualifier, you want the block to `retain` it so it
// can live after the `doSomething` method is destroyed
NSMutableArray *objArray = // created with something useful
[self performOperationWithBlock:^(void)
{
// You do something with the objArray, like adding new stuff to it (you are modyfing it).
// Since you have the __block qualifier (in non-ARC it has a different meaning, than in ARC)
// Finally, you need to be a good citizen and release it.
}];
// By the the time reaches this point, the block might haven been, or not executed (it's an async call).
// With this in mind, you cannot just release the array. So you release it inside the block
// when the work is done
}
Sync Approach:
It assumes that you need the result immediately, and it makes sense when you do further work with the Array, after the block has been executed, so:
-(void) doSomething
{
// Keep `__block` keyword, you don't want the block to `retain` as you
// will release it after
__block NSMutableArray *objArray = // created with something useful
[self performOperationWithBlock:^(void)
{
// You do something with the objArray, like adding new stuff to it (you are modyfing it).
}];
// Since it's a sync call, when you reach this point, the block has been executed and you are sure
// that at least you won't be doing anything else inside the block with Array, so it's safe to release it
// Do something else with the array
// Finally release it:
[objArray release];
}
You should release it after the performOperationWithBlock: method has finished, in my opinion, provided that method is synchronous (i.e. works on the same thread as the calling thread).
If that method is asynchronous then it should be released within the block.
If you're not using ARC, you should release the array when you no longer need it. According to the comments you added and assuming the doSomething method doesn't do anything with the array outside of the block, it should be at your 1. mark.
Option 2. Release it after [self performOperationWithBlock:...]. Block will retain and release yours objArray by himself. Releasing inside block is dangerous: block can be performed twice and then objArray will be released twice, but it's should de released once. So there is only one option left: 2.
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 :)