I have this code in non-arc, and I think it has a problem - circle retain (self (UIViewController) has the ownership of complete-block, complete-block has the ownership of self). But when I debug, it run in dealloc (mean that not have circle retain count as I think)
[self dismissViewControllerAnimated:YES completion:^{
[self goToChatViewController:buddyEntity];
}];
Can someone explain for me, why it not circle retain in this code?
You don't hold reference at this block. So this block deallocated after completion.
When block deallocating it release object that it hold.
So there is all ok. You can courageously use self inside such blocks.
Retain cycles appear for example if you use block as property or add it in container.
A block is secretly an ObjectiveC object. When you create a block in the background objectiveC creates an instance of a block class (although quite weirdly it creates it on the stack rather than the heap, unless you copy the block). The objects used inside of your block become instance variables of the block object.
Because the block object is on the heap, not on the stack normally when you get to the end of the method you are in the block object falls out of scope and everything is great. However if your class calls copy on the block, and keeps a reference, the block is copied to the heap. Now your class has a reference to the block and the block has a reference to your class and you have a retain cycle.
Related
Following this question, and more specifically, this comment:
because retain (aka strong reference) cycles in the common case where the timer's target is also its owner
I am wondering why dealloc isn't a good place to invalidate an NSTimer.
I remember profiling my app without auto-repeating NSTimer invalidation and then with invalidation in dealloc, and the memory correctly freed.
Is dealloc working differently in the latest iOS?
Isn't in fact your overridden dealloc called prior to any NSObject deallocation? What is dealloc even used for, then? If not manually deallocating the respective object's properties?
ARC will only release ( and call dealloc ) objects, when there are no strong references pointing to this object ( no one is retaining ).
NSTimer creates strong reference and it will retain target.
This means, dealloc will not be called, because NSTimer still has strong reference to the object. If there is no dealloc, this means NSTimer will never be invalidated ... leads to memory leak or even crashes.
There is a way to invalidate timer in dealloc or when target becomes nil. Have a look at the answer here.
Hi All
I am trying to dealloc a ViewController in ARC mode.
However, the RefCount is always non-zero.
I have tried to set all object to nil and all subviews to removeFromSuperview + nil;
and timer to invalidate + nil;
still the counter = 2;
Is there a way to trace which pointer is still in retain?
Thanks
If you are using blocks you might also create retain cycle there. E.g. a block is referenced by an object and inside this block you are referencing object or calling instance method for object.
Another option for retain count not dropping to 0 is that you have registered abject as observer for notification.
You might find this answer helpful:
https://stackoverflow.com/a/12286739/2261423
Example of strong reference cycle from apple docs:
self.block = ^{
[self doSomething]; // capturing a strong reference to self
// creates a strong reference cycle
};
#Billy, why are you doing this? You may not worry about deallocation when using ARC. Controller will be deallocated automatically, when there will be no references to the controller. Yes, views do not refer to controller, they are referred by it! So removing that views will not affect retain count of the controller. If you really want to remove View Controller from memory, remove it from parent view controller and set all links to nill.
I pass a completion block to my method, this completion block will be called in the background when a network request is finished. Unfortunately, if the calling object is deallocated in the meantime, the app crashes:
ViewController (which may be deallocated because it's popped from the navigation stack) code:
__unsafe_unretained ViewController *weakSelf = self;
[[URLRequester instance] sendUrl:url successBlock:^(id JSON) {
[weakSelf webserviceCallReturned:JSON];
}];
URLRequester-Code (made simpler, of course):
- (void)sendUrl:(NSString *)urlAfterHost successBlock:(void (^)(id))successBlock {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(2);
successBlock(nil);
return;
});
}
If, in this 2 seconds, the ViewController gets popped from the navigation stack, the app crashes. What am I missing?
When you use __unsafe_unretained, then the reference remains around even after the object is deallocated. So if the view controller gets popped, then weakSelf is now pointing to a deallocated object.
If you change it to __weak instead, then when the view controller gets deallocated, it will set weakSelf to nil, and you'll be fine. You don't even need to do a check for if weakSelf is set to anything, because calling a method on nil has no effect.
It seems quite a few people think that 'self' inside a block must always be a weak (or unretained) copy. That's usually not the case**.
In this situation the misunderstanding is causing the crash, by leaving a zombie around. The right thing to do is to refer directly to self in the block (not unsafe_unretained, not weak), just like you'd like normal code to look. The effect will be that the block will retain the instance pointed to by 'self' -- the view controller in this case -- and it won't be destroyed until the block is destroyed (presumably by the url requester).
Will it be damaging to the view controller to process the result of the web request even though it has been popped? Almost certainly not, but if you think it will be, check for that condition in the block.
if (![self.navigationController.viewControllers containsObject:self])
// I must have been popped, ignore the web request result
// Re the discussion in comments, I think a good coder should have misgivings about
// this condition. If you think you need it, ask yourself "why did I design
// my object so that it does something wrong based on whether some other object
// (a navigation vc in this case) contains it?"
// In that sense, the deliberate use of weakSelf is even worse, IMO, because
// it lets the coder ignore _and_obscure_ an important question.
else {
// do whatever i do when the web request completes
}
**The need for weak or unretained pointers in blocks stems from the fact that blocks will retain the objects they refer to. If one of those objects directly or indirectly retains the block, then you get a cycle (A retains B which retains A) and a leak. This can happen with any object to which the block refers, not just 'self'.
But in your case (as in many) the view controller referred to by self does not retain the block.
The good practice in using block (especially delayed ones) is to make a local copy of the block in the calling method. In your case it should be done in -(void)sendUrl:successBlock:
successBlockCopy = [successBlock copy];
and then call
successBlockCopy(nil);
It should retain your viewController for a while until completion.
Also it is better to use __weak instead __unsafe_unretained to avoid problems with suddenly released objects.
I have two View Controllers, one with a grid of buttons, and the second one is a detailed description based on the button the user presses.
I'm using "Mark Heap" in Instruments allocations tool and finding that my app is increasing in memory after the user sees the detailed View Controller and then presses the back button in the navigation bar. IT should result in a net change of zero for memory... I'm using ARC, xcode 4.2.1, deploying to ios 5.0+
When I load the new ViewController after the button press, I load some data images in a background thread. Is it possible that because I'm pressing the back button quickly, that data is still being loaded in the background thread and is never released from memory?
from the slides from the class i had that described memory cycles problem you may be facing:
what if you had the following property of a class?
#property (strong, nonatomic) NSArray* myBlocks; // array of blocks
and then tried to do the following in one of that class's methods?
[self.myBlocks addObject:^() {
[self doSomething];
}];
all objects referenced inside a block will stay in the heap as long as the block does. (in other words, blocks keep a strong pointer to all objects referenced inside of them.)
in this case, self is an object referenced in this block. thus the block will have a strong pointer to self. but notice that self also has a strong pointer to the block (through its myBlocks proeprty)
THIS IS A SERIOUS PROBLEM!
neither self nor the block can ever escape the heap, now. that's because there will always be a strong pointer to both of them (each other's pointer). this is called a memory "cycle".
solution:
local variables are always strong. that's okay, because when they go out of scope, they disappear, so the strong pointer goes away. but there's a way to declare that a local variable is weak. here's how ...
__weak MyClass* weakSelf = self;
[self.myBlocks addObject:^{
[weakSelf doSomething];
}];
this solves the problem because now the block only has a weak pointer to self. (self still has a strong pointer to block, but that's okay) as long as someone in the univese has a strong pointer to this self, the block's pointer is good. and since the block will not exist if self does not exist (since myBlocks won't exist), all is well!
I've become a little paranoid with blocks and the possibility of creating a retain cycle. I'm using a block based version of the UIAlertView class which allows you to use blocks instead of delegate methods. I use a lot of these Alertviews, so I'm often calling into instance methods that do a lot of heavy lifting.
Would the assignments I make in the method someInstanceMethod cause a retain cycle?
(I am using ARC for memory management.)
__weak id weakSelf = self;
[doWorkAndThen:^{
[weakSelf someInstanceMethod];
}];
-(void) someInstanceMethod{
//will either of the assignments below cause a retain cycle?
self.iVar = #"data";
[self setIvar:#"data";
}
No. -someInstanceMethod is not a block. The fact that you're calling it from one is irrelevant. Only references inside the block itself can cause retains, and since your only reference inside your block is a __weak variable you're fine.
Incidentally, if you really want to ease your mind, you should modify your block-based UIAlertView class to throw away all the blocks when the view is dismissed. This way even if you do create a retain cycle, it will be broken automatically as soon as the alert view goes away.