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.
Related
In ios6 should I set strong IBOutlet to nil when receive memory warning? what about a view I declared as instance variables and added to the view hierarchy by code?
Since iOS6, Apple recommends not releasing views, just cached data that you can recover easily, such as downloaded images. This is why they deprecated viewDidUnload.
On top of Leo Natan's answer, it also wouldn't do you any good to just set the outlet to nil, as you would also need to remove the outlet from its superview. Before that you would need to check that the view property isn't visible (has no window property) as well as clearing out the view. It's complicated and unnecessary.
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).
in my app, sometimes I get a level 1 memory warning which I think is acceptable given the amount of work it is doing. When that happens, it calls the viewdidunload for one of the views which is part of the tabbarviewcontroller. In the viewdidunload, i set the outlets to nil which I think is totally normal.
The issue arises if I try to access that class again. Since it was deallocated, it will throw a bad access error which prevents me from showing that view again. If I don't set those outlets to nil then it won't crash which is normal but the convention is always to set any outlets to nul in the viewdidunload.
Any pointers for handling memory warnings in this case? I don't want to delete the code i have in the viewdidunload method since it is going against the convention.
I forgot to add that i subclassed the tabbarcontroller >_<
In that case, again the subviews added to xib file will be allocated when you load that view again. And if you want to customize something, do that in viewDidLoad method.
Where do the views which were deallocate get allocated? It sounds like you are deallocating a view in viewDidUnload that was not allocate in, for example, viewDidLoad. Instead it might have been created somewhere else, so it does not get recreated then the viewController's view is reloaded.
My app is nearly finished and I have been Profiling it using Instruments. I'm checking out retain counts of various objects.
I have been careful to release any objects which I have called alloc on, and these don't seem to be leaking - so thats cool.
However, I have a view controller which has a UIPickerView in it. I set that up by dragging it onto my NIB in IB, defined the property using IBOutlet, synthesized it, and then hooked it all up.
Every time I launch the view, it seems the number of UIPickerViews increases by one. I was under the assumption that I do not need to release this kind of thing myself, as I had assigned it to a property (using nonatomic, retain).
This is happening to all my UI stuff - buttons etc, not just the picker view. I was just using that as an example.
Can anyone help me out here?
Thanks!
When the view is loaded all the items created from the NIB are retained for you and your IBOutlet pointers are initialized pointing to those retained subview objects. You need to release those in viewDidUnload. Are you doing that?
In viewDidUnload you should release all objects created from the NIB and set those pointer to nil. You should also release those same object in dealloc. Example here.
They say:
// Release any retained subviews of
the main view. // e.g. self.myOutlet =
nil;
I've never seen that previously. so I wonder if they talk about nib outlets here?
Similar to how anything you allocate in init should be unallocted in dealloc.
If you alloc memory in viewDidLoad, you should release it in viewDidUnload.
The issue gets confusing when you bring nib files into the picture. If you are manually loading the nib file, you should manually unload it and set all the IBOutlets to nil.
You don't have to if there is a reason to keep it around, but assuming you need to access the entity point to via the outlet if the view has been torn down then yes, you should release. Otherwise your view controller will be asserting a retain against all of the IBOutlets from yoour nib even though the nib itself has been unloaded, which prevents them from being dealloced. Since these objects may have textures and such backing them, and the iPhone uses main ram for video that can add up to a lot of wasted memory very quickly.
Additionally, if viewDidLoad is called again then a new object will have been created and assigned to that outlet when the nib is reloaded, so if you use it anywhere else (set properties in other objects to the object pointed to by the IBOutlet) then your app might end up in an inconsistent state.