Reputation: 3114
An application that I am working on, that uses ARC
and needs to support iOS 4.3 and iOS 5, declares every outlet
as @property (strong, nonatomic) IBOutlet
in the .h
file.
e.g.
// myClass.h
@property (strong, nonatomic) IBOutlet UITextView *myTextview;
I know that with ARC
only properties which do not hold a strong
reference to an object are released.
As a result, the App relies on - (void)viewDidUnload
to set the property myTextview
to nil
.
i.e.
// myClass.m
- (void)viewDidUnload
{
[super viewDidUnload];
self.myTextview = nil;
}
I know, from Apple's Documentation, that Outlets
should generally be weak
except those from File's Owner ( i.e. A Runtime Object
that owns the contents of the iOS Storyboard scene) to Top-Level Objects
(my rule of thumb is to use anything that appears in the window with File's Owner, First Responder and View).
Anything I add to the view
will be a subview
and thus is retained
by it's direct superview
, meaning a weak
reference should be used.
I am also aware that - (void)viewDidUnload
is deprecated in iOS 6 and is not called.
1st Question : What are the issues with taking the approach of declaring every outlet as a strong
property and setting it to nil
in viewDidUnload
, apart from the fact that viewDidUnload
is deprecated in iOS 6?
My intuition tells me that it is because situations arise where you can set a pointer to nil
, before viewDidUnload
is called. So you should, to free up memory on the heap. Is there a noticable performance change if this is the case?
2nd Question : Should I go back throughout the project and change strong
to weak
? Why? Is it worth the time?
3rd Question : If I was to declare the property
in a class extension
, to 'hide' it, how does this affect my rule of thumb for deciding on when to use strong
or weak
.
I know there are many threads here that discuss this issue. But many I've found are out of date, and do not address this issue directly. Thanks.
Upvotes: 1
Views: 694
Reputation: 20153
First, a few of your presumptions need addressing:
I know that ARC only releases properties which do not hold a strong reference to an object. As a result, the App relies on - (void)viewDidUnload to set the property myTextview to nil.
Not quite. ARC never retained weak
properties in the first place. As for strong
properties, ARC still releases them, but not until dealloc is called.
viewDidUnload
was never used to prevent leaks. It was essentially an optimization, and one that Apple decided was no longer worth the trouble. To understand, consider the standard lifecycle of a pre-iOS6 view controller:
1. Allocated
2a. View Loaded
2b. View Unloaded
3. Deallocated
Where 2a and 2b could be repeated any number of times. For example, a view controller at the bottom of a navigation stack (its view being hidden) could have its view unloaded in low memory situations. It would then be reloaded the next its view became visible.
The method was essentially saying "Hey view controller programmer, we're running low on memory, and nobody can see me anyways, so I'm releasing my view. If you could do the same for your strong properties, that would be great."
That process had subtleties and was generally confusing. As a result of the tediousness, Apple deprecated it. Views are no longer unloaded, so there's no point in implementing it. The key point is that all your strong properties will still be released in ARC's dealloc method.
I know that Outlets should generally be weak...
Why do you know that? There's nothing special about outlets. The 'IBOutlet' keyword is really just for Xcode's benefit when designing things with its visual tools. It has no effect on the compiled code. So, when thinking about strong
vs weak
outlets, use the same considerations that you do for any other property, namely "do I need this to exists, or am I okay with it disappearing on me?".
What are the issues with taking the approach of declaring every outlet as a strong property and setting it to nil in viewDidUnload, apart from the fact that viewDidUnload is deprecated in iOS 6?
There are no issues with that. If you want your properties to exists as long as your controller, then use strong
. viewDidUnload
has nothing to do with this. On older iOS versions, you could release strong outlets in viewDidUnload
if you want.
Should I go back throughout the project and change strong to weak? Why? Is it worth the time?
Again, just use whichever qualifier makes sense for your use case. You're almost always safe using strong
for you outlets.
If I was to declare the property in a class extension, to 'hide' it, how does this affect my rule of thumb for deciding on when to use strong or weak.
There's no difference.
Upvotes: 4
Reputation: 15217
1st question: The outlets are subviews of the main view which is a property of the view controller. If you declare them as weak
, they have a retain count of 1, since they are subviews. If the view is released, they are also released. If you declare them as strong
, they have a retain count of 2, since they are subviews, and strong properties of the view controller. So they are only released when the view controller is released (which releases also its view and its subviews). To my understanding, the difference is that when the view of a view controller is released, e.g. when it is not presented and memory is low, the outlets still allocate memory when they have been declared as strong
.
2nd question: I believe in most circumstances it does not matter.
3rd question: I believe if you declare properties in a class extension, the simply belong to the class, and thus there is no difference in handling them compared to "real" class properties.
My approach would be to make sure not to declare properties as strong
that could result in retain cycles, what happens, i.e., if you declare a delegate as strong
.
Upvotes: 0