I have an interesting question about interface builder and ARC. I am building a view controller that will be initialized with a xib. I use the tap-and-drag capability of interface builder to create necessary property outlets for my xib. This initalizes the property as (weak, nonatomic). Sounds fine to me.
What's throwing me off is that lines such as [self setCategoryButton:nil]; are automatically added to viewDidUnload. I understand and used this before ARC. However, since these are weak references, wouldn't they automatically be cleared when the view unloads?
I suppose I could see the value in nil-ing these properties if those views are retained by other objects, but that seems an unusual case to me... Just wanted to get further feedback on the point.
Thanks,
Kurt
I filed a bug on this a while back, and the response that I got was that this is intentional behavior. Since Xcode cannot verify that there are no other strong references to the view, it cannot actually guarantee that the weak pointer would be automatically cleared in -viewDidUnload. Thus, they clear it for you.
Personally, I think this is a lame reason, but that's the reason that was given.
It will only be set to nil in iOS5 or later (iOS 4 does not automatically nil weak pointers), so it is there for safety in the auto generated code. I've been wondering about this myself and that's the only reason I can come up with.
From Documentation, the viewDidUnload
"This method ...is your chance to perform any final cleanup. ... "
"When a low-memory condition occurs and the current view controller’s views are not needed, the system may opt to remove those views from memory"
From Documentation, about weak (Setter Semantics)
Specifies that there is a weak (non-owning) relationship to the destination object.
If the destination object is deallocated,the property value is automatically set to nil.
So it's obvious. It's consistant on the rules.Is not about the object that your property points,but just nullify your property based on the above rule of weak.
The viewDidUnload suppose that's your weak property can't be point to any object,
because that object is deallocated (based on the place of viewDidUnload in the life cycle of a View Controller). And simply cleans it with the nil.
It's safe for you, explicit to the weak rule and memory efficient.
The compiler can't be sure that you took the care about the pointed object.
He just need to ensure the clean up.
Since the property is weak, the reference in your object won't affect the retain count of the object. So yes, there's no point in setting the object as nil. At least that's how I understand it.
Related
I am new to ARC. My issue is that if we create a strong type property on a view controller, we need to make it nil once the navigation controller's popViewController happens.
Normally, we would do that in viewDidUnload. But in iOS 6 it's deprecated.
So where do we make that object nil? Apple says to do it in didReceiveMemoryWarning but that method does not get called every time when we pop the view controller.
Don't worry about it. Your properties will all get set to nil automatically by the Objective-C runtime in dealloc. This is true of all properties, not just outlets on a view controller.
You define a property strong if you want to keep ownership on the referenced object.
From what I can understand you probably need a weak property (when your object is released by someone else you don't need it and it can be deallocated) or maybe a workaround could be set it to nil in the viewDidDisappear method, but as Jim Puls said, without seeing you code mine are just educated guesses...
If you're popping/pushing between the same two view controllers, then the pointer in the UINavigationController shouldn't change as long as they don't get dealloc'ed. If they do get dealloc'ed then everything in them should get dealloc'ed too. You may end up creating new copies of these view controllers but that shouldn't be a problem because you're only creating new copies if the old ones were already dealloc'ed. The only way you can be retaining objects is if your view controllers (or objects within them) are referencing each other, causing them to be retained.
The difference between strong and weak is not that you need to manually set strong to nil. Rather, a strong relationship will cause an object to be retained, while a weak will not. That's why delegates are usually set to weak since you don't want a delegate retaining its parent (not parent exactly, but the object that it's a delegate of).
What is the significance of setting the properties to nil in viewDidUnload in both the aspects i.e. with ARC or without ARC?
Does it only matter in case of IBOulets? Don't we need to set the other properties (that are not IBOulets) to nil?
What can be the consequences if I don't do that? I haven't set them nil before and haven't observe any consequences.
Help is really appreciated.
Setting IBOutlets to nil in viewDidUnload tells the compiler to release the outlets on memory warning.because on memory warning ..viewDidUnload and didReceiveMemoryWarning of the viewcontrollers gets called..Normally in ViewDidUnload the IBOutlets are set to nil and in didReceiveMemoryWarning properties or objects are released.Hence in such a case memory is regained and thus your app can continue to function else continuous pooling causes in crash due to low memory
After reading a lot articles on the web and going through similar questions on stackoverflow.com I reached at the following understanding:
viewDidUnload is called by the compiler in low memory situation.
We should set those properties to nil in the method, which are being re-instanciated in viewDidLoad. Almost all IBOutlet components falls under the category. So better we declare the IBOutlets to nil in the method. Not doing so will lead to continuous pooling and may cause crash due to low memory in future(the time, the app continues to run).
I also read that we should not nil the instances of the class like NSString(may cause crash), which is right as per my experience. But reason for that I don't know.
It has nothing to deal with ARC. Setting a property to nil simply means that the property doesnot keep the refrence of any memory location anymore.
I will keep on updating this answer every time i came to know something more about it.
Thanks.
I am new to iphone development . I am using ARC for my project. As far as I understood using ARC we don't have to release any object manually. But , I have observed in some places , people explicitly set their object to nil in the ViewDidUnload even after using ARC.
For example, in .h file I have something like this:
#property (unsafe_unretained, nonatomic) IBOutlet MKMapView *mapViewOutlet;
#property (unsafe_unretained, nonatomic) IBOutlet UIToolbar *toolBar;
#property (strong,nonatomic) NSMutableArray *dataArray;
And .m as follows:
- (void)viewDidUnload
{
[self setMapViewOutlet:nil];
[self setToolBar:nil];
[super viewDidUnload];
self.dataArray=nil;
}
My question is, is it really necessary to explicitly specify nil in the ViewDidUnload even under ARC?
The whole point of the viewDidUnload method is to release data that you don’t really need, in order to free memory. Read the documentation:
When a low-memory condition occurs and the current view controller’s
views are not needed, the system may opt to remove those views from
memory. This method is called after the view controller’s view has
been released and is your chance to perform any final cleanup. If your
view controller stores separate references to the view or its
subviews, you should use this method to release those references. You
can also use this method to remove references to any objects that you
created to support the view but that are no longer needed now that the
view is gone. You should not use this method to release user data or
any other information that cannot be easily recreated.
So you’re setting the properties to nil in order to release the objects now and help the system to free up some memory. But of course this depends on the property type – strong properties are “yours” and only you can decide whether to release them now (by setting to nil) or not. Weak properties could already be nil, for example if they pointed to some views that got released with the main view. And unsafe_unretained properties are a special beast. The object they point to might already been released, but that does not mean they were set to nil automatically. So you should either use one of the “safer” property types (strong/weak), or set the unsafe properties to nil here, to make sure you won’t use the released object later. There are no hard rules in this case, you have to think about the situation and what it means for the various properties.
By the way, viewDidUnload is getting deprecated in iOS 6, where no views are being released under low-memory conditions anymore. You still receive the didReceiveMemoryWarning callback, so that you can release some resources there if you want to. Again, I suggest that you read the documentation and run a few tests to see what happens and decide what you should do.
ARC will only release properties which do not hold a strong reference to an object. In your case, these are all strong references, so they will be kept unless they are explicitly set to nil.
The viewDidUnload method does not mean that your UIViewController is removed from memory, it simply means that its views are removed from memory (iOS Developer - ViewController lifecycle).
In this case, your UIViewController remains in memory, and therefore its properties as well, unless they are explicitly set to nil.
When you are using unsafe_unretained, you should assign it to nil because it will not be assigned to nil implicitly, where is case of weak reference it will be assigned to nil implicitly.So in order to avoid any dangling reference you need to assign to nil in case of unsafe_unretained.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Should IBOutlets be strong or weak under ARC?
I read about ARC briefly and thought ok, everything is strong and delegate is weak.
Now I'm creating a view in interface builder and making IBOutlets, and Xcode's default setting is set to weak.
There seems to be a reason for this suggestion, is there a reason most IBOutlets would want weak property?
Is that because these views(IBOutlets) are already retained because they are attached to its superview? and we seldom replace IBOutlet views?
But I don't see a harm in setting it as strong, is there a problem with it?
For a discussion of why IBOutlet references should be weak, see the Resource Programming Guide: Nib Files. I quote from the guide:
Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create should therefore typically be weak, because:
Outlets that you create to subviews of a view controller’s view or a window controller’s window, for example, are arbitrary references between objects that do not imply ownership.
The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet).
For my own two cents, I make things strong if I own it, or I need a strong reference in case the owner goes away and I need it to be retained, neither of which apply here. So, rather than asking, "why can't I make it strong?", I'd ask "why would I want to make it strong?" If there's no good reason to do so, I'd let Interface Builder do it's thing and make it weak.
It's just preference. The rationale for weak or assign is that the superviews, controllers, etc will hold strong references during the object's lifetime within that graph.
Personally, I am old school, and favor strong references -- even in this scenario. At times, using strong references means you may need to explicitly destruct components of your objects' subgraphs (e.g you must 'break' all circular dependencies when tearing down). I only use weak in very exceptional circumstances because I favor consistency; There are fewer variables at play when/if when something goes wrong and when reading programs.
I'm not entirely new to iPhone dev, but I ran across a situation where I was unsure about the best design choice for my code.
I have a view controller which asynchronously fetches an image from the internet and loads it into an image view. When the app receives a memory warning however, the imageView is released by didReceiveMemoryWarning. If the app receives a memory warning while loading an image, the imageView is nil by the time my code tries to load the image into the imageView.
What is the best practice for viewDidLoad? Should I just instantiate any variables that I may need later on? Or should I just check for nil values elsewhere in my code?
Also, in viewDidUnload, should I just set IBOutlet variables to nil? Why is this?
Thanks! -Matt
Why not just create the image view on demand when the image is loaded? No need to create it any earlier. Or, if you do, then just have code to recreate it if it has been released.
In viewdidunload you should release resources that you created in viewdidload (or load view). Including any IBoutlets that interface builder hooked up for you. It's good practice to set these variables to nil to ensure they won't be inadvertently accessed after release, or double released.
IBOutlets can be both instance variables and properties. In both case, we should release the references when the view, which is top most superview, is unloaded. Setting the IBOutlet retained properties to nil releases the reference automatically, but for instance variables we need to release them. We still need to set instance variables to nil because viewDidUnload is not dealloc, so we must comply with the managed memory rule or we might have invalid references sitting around inside the instance.
I don't think there are rules about what you should do in viewDidLoad, but if you did release and set some variables to nil in viewDidUnload, you need not have to check for nil again in the viewDidLoad unless you don't trust the framework.