A few questions about ARC for iOS? - objective-c

I'm fairly new to ARC for iOS (and pretty new to iOS in general) and I have a few quick questions about ARC.
~ In a View Controller, if I do not have statements in my viewDidUnload() method setting my properties to nil, will the properties' memory still be freed when my view controller is released? If so, why do I need to explicitly have this viewDidUnload method?
~ In objects that are not View Controllers, where should I set the properties to nil at? In dealloc? What about primitive properties such as #property BOOL isActive;...do I need to set them equal to nil/zero?
Thanks.

You don't need to set your properties to nil as long as they're weak references. IBOutlets should generally be weak references, since they the view controller contains a strong reference to the view, which in turn contains strong references to all of its subviews. (If you have IBOutlets that aren't part of that view hierarchy, they should be strong.)
You shouldn't need nil or zero anything, objects or scalars. Xcode will insert nilling statements when working with Interface Builder, but this is it still generating code for pre-ARC Objective-C.
You probably don't even need a viewDidUnload; it's only called in special circumstances, when there's low memory stress. Thus, you can't depend on it for cleaning up. Your IBOutlets should be weak, so they'll be cleaned automatically when the view is purged from the viewcontroller (and they'll be restored if the view is reloaded).
I'm assuming here that you're writing a new product, which means you're targeting iOS 5 or later only. If you're targeting iOS 4 in a new product, you really shouldn't be. The world has moved on, with 80% of the market on iOS 5 or later. And that's today. Going forward, it's going to be even harder to avoid iOS 5 features for an even smaller percentage of people.

Memory management for #properties is handled automatically under ARC. For times when you have set yourself as delegate, it is common to set the delegate to nil before going away (in viewWillDisapear for instance) so that future calls to delegate don't reference garbage. Stay tuned for the soon-to-be-posted WWDC videos for the latest guidance.

In viewDidUnload you need to set outlet references to nil, because ARC will release them and you do not want to accidentally use them after that happens.
You don't have to do anything with properties, they will be handled automatically. In fact you really do not normally even have a dealloc method any more with ARC.

Related

How does the release work in ARC based projects

I know there are lot of questions on this topic. I have never worked on Non ARC based project.
I have strong & weak property as follows
#property(strong,nonatomic)NSArray *data1;
#property(unsafe_unretained, nonatomic)NSArray *data2;
I have seen in some places people explicitly make the data nil in the viewDidUnload.
i.e
-(void)viewDidUnload{
self.data1=nil;
self.data2=nil;
}
My question is if I dont do this in my case(I mean if I dont make the data1 and data2 nil
in the viewDidUnload), Will ARC release the objects automatically ?
Yes, they will be released when your view controller is deallocated. viewDidUnload (no longer called as of iOS 6) is not the same as dealloc, nor is it an "opposite" of viewDidLoad - it was only called in low memory situations, when a view was off screen.
Any transient, memory-hogging objects should be set to nil in didReceiveMemoryWarning - ARC will not do that automatically for you.
Yes, ARC will automatically release all strong-reference properties/variables just before the destruction of the parent object. As for "weak" references, they are not retained/released (that's the same with or without ARC).
Setting self.data1 = nil in viewDidUnload is usually unnecessary, but sometimes you want to make it obvious to show where your referenced object is released. If you want to be sure that your data1 is released right here at this line of code, use the code you have. If you don't care when and where it's released, you don't have to.

Differences between weak and unsafe_unretained

So I had a project that supported iOS 4, so all my IBOutlets were __unsafe_unretained even IBOutlets that were in the nib but outside the controllers main view (Separate View in the same nib) and all worked great.
So the time has come and now the client wants to support only iOS 5 so our team changed all the __unsafe_unretained IBOutlets for __weak IBOutlets but now the IBOutlets that are not inside the main view are set to nil (except in viewdidload) so we are unable to add them later.
If I think about it, it makes sense because if no view (main view) is retaining those IBOutlets they should be deallocated and zeroed (I don't know if that is the correct word), so the solution is to remove the __weak from those IBOutlets
But what doesn't make sense to me is Why the different behavior between unsafe_unretained and weak, in my head the unsafe_unretained ones should be deallocated and when the app tries to access them, they should point to an invalid reference and then the app should crash.
I thought that unsafe__unretained was the same as weak but without the zeroing.
Am I missing something here?
Thanks.
I thought that unsafe__unretained was the same as weak but without the zeroing.
It is, yes.
When Cocoa loads the nib, it creates all the objects autoreleased, so they are still there when viewDidLoad is invoked. However, the autorelease pool has a lifetime that ends when control returns to the run loop. At this point all the objects that aren't owned by anything will go away so any weak outlets will be zeroed at that point.
For most outlets, this is not a problem because objects in the NIB are already generally owned by something anyway. So, for instance, a button in a view is owned by its parent view. Having strong outlets that point to that button are therefore overkill or worse might result in a retain cycle.
Top level objects obviously don't have a parent view to own them so they need to be owned by something else e.g. a controller or "File's Owner". If you are finding stuff disappears, you need to create a strong IBOutlet for it in File's owner.
For more detail, see Apple's docs.
For future searchers who come across this question, I think CRD's Stackoverflow answer to a similar question may explain. Even though the object has been deallocated, the memory that's referenced by the unsafe unretained pointer (which contains the actual object data) is not necessarily zeroed, so things may appear to behave properly until that memory is actually reused/modified/zeroed.
You are correct, the app will crash when trying to access deallocated objects through your stale __unsafe_unretained references.
The reason it doesn't is very likely because the objects are being referenced by some other part of your app with strong references.
Try running with zombies enabled, that should cause an immediate crash when dereferencing the presumedly stale pointers.

When removing dynamically created objects in Objective-C, what should I set to nil?

Easy question alert, but I want to be sure I'm not being stupid.
In my iPad app I'm dynamically creating a UIView, and filling it with UIButtons, UIImageViews, sometimes a MPMoviePlayerController, sometimes a UIImageView with a few UIImages as an animation.
After a certain amount of time, I'm removing the view from the screen and discarding it.
The question is: should I be setting any of these objects to nil?
I'm releasing everything after I allocate it, and I'm not getting any leaks. BUT my app is eventually crashing after running out of memory. Each one of these views I build seems to be lurking somewhere in memory.
Any help, much appreciated.
Duncs
It's hard to comment without code or knowing if you are using ARC or not (guessing not, because you said "releasing").
Do an Analyze and fix every problem it flags. It's very good at telling you if you are retain/releasing correctly
Use the Leaks Instrument to find leaks
If you have no more leaks, but are still crashing, then turn on Zombies and make sure you aren't releasing anything too early
Setting a variable to nil doesn't do anything to release the memory. If you have a #property that is declared with (retain), the auto-generated setter will make it so setting the property to nil will release the old value.
The dealloc of any class that has properties needs to do this to all properties that are pointers to retained objects. For UIViewControllers, you would also want to do this in viewDidUnload for IBOutlet properties.
When you are using ARC, while you add the UIView as subview of another UIView, the retain count will increase. On you "removeFromSuperview" it, it will decrease and it will be deallocated. In a Non-Arc environment, after allocating it and adding it to a UIView the retain will be of 2, but then you release it, so it will go back to 1. So there is always a balance between those. To check what's going on, you should use Instruments, to pinpoint the problem.
It only makes sense to "nil" it is when you have a #property of the iVar (for retain). Why is that? Because it will release the old value and it will set the new one to the value passed (in this case nil). You probably think that the issue is related the UIViews but might be something else. That's why I advise you to use Instruments.

Interface Builder sets control outlets to nil -- why?

Using xcode 4.2 for iPhone app, without ARC ---
When I create an outlet using the interface builder xcode adds two lines of code to my viewController. One in viewDidUnload: -- [self setMyOutlet:nil] and second in dealloc -- [myOutlet release].
I understand the latter (the release). But why set the outlet to nil in viewDidUnload. Doesn't viewDidUnload get called before dealloc and won't setting the outlet to nil negate the release operation in dealloc? Setting to nil makes sense I would think for building a Mac application which is using garbage collection -- but it doesn't make sense for an iPhone app.
Why does the interface builder do this? Should I delete the lines which set the outlets to nil?
viewDidUnload may be called and may be not called. It depends on the current memory usage. dealloc is a place where you should clean all your properties (like arrays, custom objects). In viewDidUnload you clean views and perhaps objects created to support the view. viewDidUnload mean that your view is unloaded (but not whole view controller) and it may be created and loaded again (in viewDidLoad, of course) in the future.
Why to nil - Objective-C Difference between setting nil and
releasing
Understanding How Views Are Loaded and
Unloaded
viewDidUnload is not called everytime before a dealloc, see what the apple docs say..
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 the idea behind it is too release any unwanted objects which can be created easily.
Now coming to the part where it sets the properties to nil.. it does so because this way you release all the memory and set the objects to nil (thus bringing your down your memory usage) and after this if a dealloc is called your app will not crash as in objective-c you can send release messages to nil objects..
I would advise you to read the apple ViewController Programming Guide , it will clear a lot of your questions.... hoping this clears some of the air.. :D

Keeping pointers to subviews

Subviews added to a view are automatically retained by the view. Suppose you want to have a separate pointer to the same subview so you don't need to constantly retrieve it via its tag.
What type of #property is necessary for such a case? I assume that setting the property to retain is not a good idea since the main view is already retaining it? Should it be assign?
Or, is using #property entirely unnecessary here unless you plan to re-assign it later or refer to it with dot notation?
You can use either retain or assign.
Of course, if you use retain, you have to set the property to nil or release its object in viewDidUnload and dealloc.
The reason some people prefer retain is because it means the property is still valid in viewDidUnload. So if you have other cleanup to do, and that cleanup requires the view to still exist, you can do it in viewDidUnload.
If you use assign, you don't have to set the property to nil in viewDidUnload and dealloc (though it would be good practice). However, by the time you receive viewDidUnload, the view has already been released, so you can't use it at that point for other cleanup. Instead you have to override didReceiveMemoryWarning to do the cleanup before calling [super didReceiveMemoryWarning].
In iOS 5.0, you can do the cleanup in viewWillUnload instead of overriding didReceiveMemoryWarning.
Consider these two things:
There's no problem with retaining an object several times provided that each retain is balanced with release. With respect to properties, this just means that you should set your property to nil when you're done with it.
The basic idea behind memory management in Objective-C is that you worry about retaining the objects that you're using and let other objects worry about the objects that they're using.
Considering these, I'd advocate using retain. If you rely on he fact that a view retains its subviews, you've suddenly made your code dependant on external behavior. I'm not saying that UIView is likely to stop retaining its subviews, but if you keep a non-retained reference to a subview and later remove that subview from its superview you're code is likely to crash.
Some folks do use assign for outlets pointing to subviews when they know those subviews will never be removed. Personally, I don't see the point of relying on another object to retain something for you when retaining that thing yourself is so simple and cheap.