I am developing exclusively for iOS 5 using ARC. Should IBOutlets to UIViews (and subclasses) be strong or weak?
The following:
#property (nonatomic, weak) IBOutlet UIButton *button;
Would get rid of all of this:
- (void)viewDidUnload
{
// ...
self.button = nil;
// ...
}
Are there any problems doing this? The templates are using strong as are the automatically generated properties created when connecting directly to the header from the 'Interface Builder' editor, but why? The UIViewController already has a strong reference to its view which retains its subviews.
WARNING, OUTDATED ANSWER: this answer is not up to date as per WWDC 2015, for the correct answer refer to the accepted answer (Daniel Hall) above. This answer will stay for record.
Summarized from the developer library:
From a practical perspective, in iOS and OS X outlets should be defined as declared properties. 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 will therefore typically be weak by default, because:
Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, 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).
#property (weak) IBOutlet MyView *viewContainerSubview;
#property (strong) IBOutlet MyOtherClass *topLevelObject;
The current recommended best practice from Apple is for IBOutlets to be strong unless weak is specifically needed to avoid a retain cycle. As Johannes mentioned above, this was commented on in the "Implementing UI Designs in Interface Builder" session from WWDC 2015 where an Apple Engineer said:
And the last option I want to point out is the storage type, which can
either be strong or weak. In general you should make your outlet
strong, especially if you are connecting an outlet to a subview or to
a constraint that's not always going to be retained by the view
hierarchy. The only time you really need to make an outlet weak is if
you have a custom view that references something back up the view
hierarchy and in general that's not recommended.
I asked about this on Twitter to an engineer on the IB team and he confirmed that strong should be the default and that the developer docs are being updated.
https://twitter.com/_danielhall/status/620716996326350848
https://twitter.com/_danielhall/status/620717252216623104
While the documentation recommends using weak on properties for subviews, since iOS 6 it seems to be fine to use strong (the default ownership qualifier) instead. That's caused by the change in UIViewController that views are not unloaded anymore.
Before iOS 6, if you kept strong links to subviews of the controller's view around, if the view controller's main view got unloaded, those would hold onto the subviews as long as the view controller is around.
Since iOS 6, views are not unloaded anymore, but loaded once and then stick around as long as their controller is there. So strong properties won't matter. They also won't create strong reference cycles, since they point down the strong reference graph.
That said, I am torn between using
#property (nonatomic, weak) IBOutlet UIButton *button;
and
#property (nonatomic) IBOutlet UIButton *button;
in iOS 6 and after:
Using weak clearly states that the controller doesn't want ownership of the button.
But omitting weak doesn't hurt in iOS 6 without view unloading, and is shorter. Some may point out that is also faster, but I have yet to encounter an app that is too slow because of weak IBOutlets.
Not using weak may be perceived as an error.
Bottom line: Since iOS 6 we can't get this wrong anymore as long as we don't use view unloading. Time to party. ;)
I don't see any problem with that. Pre-ARC, I've always made my IBOutlets assign, as they're already retained by their superviews. If you make them weak, you shouldn't have to nil them out in viewDidUnload, as you point out.
One caveat: You can support iOS 4.x in an ARC project, but if you do, you can't use weak, so you'd have to make them assign, in which case you'd still want to nil the reference in viewDidUnload to avoid a dangling pointer. Here's an example of a dangling pointer bug I've experienced:
A UIViewController has a UITextField for zip code. It uses CLLocationManager to reverse geocode the user's location and set the zip code. Here's the delegate callback:
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
Class geocoderClass = NSClassFromString(#"CLGeocoder");
if (geocoderClass && IsEmpty(self.zip.text)) {
id geocoder = [[geocoderClass alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (self.zip && IsEmpty(self.zip.text)) {
self.zip.text = [[placemarks objectAtIndex:0] postalCode];
}
}];
}
[self.locationManager stopUpdatingLocation];
}
I found that if I dismissed this view at the right time and didn't nil self.zip in viewDidUnload, the delegate callback could throw a bad access exception on self.zip.text.
IBOutlet should be strong, for performance reason. See Storyboard Reference, Strong IBOutlet, Scene Dock in iOS 9
As explained in this paragraph, the outlets to subviews of the view
controller’s view can be weak, because these subviews are already
owned by the top-level object of the nib file. However, when an Outlet
is defined as a weak pointer and the pointer is set, ARC calls the
runtime function:
id objc_storeWeak(id *object, id value);
This adds the pointer
(object) to a table using the object value as a key. This table is
referred to as the weak table. ARC uses this table to store all the
weak pointers of your application. Now, when the object value is
deallocated, ARC will iterate over the weak table and set the weak
reference to nil. Alternatively, ARC can call:
void objc_destroyWeak(id * object)
Then, the object is
unregistered and objc_destroyWeak calls again:
objc_storeWeak(id *object, nil)
This book-keeping associated
with a weak reference can take 2–3 times longer over the release of a
strong reference. So, a weak reference introduces an overhead for the
runtime that you can avoid by simply defining outlets as strong.
As of Xcode 7, it suggests strong
If you watch WWDC 2015 session 407 Implementing UI Designs in Interface Builder, it suggests (transcript from http://asciiwwdc.com/2015/sessions/407)
And the last option I want to point out is the storage type, which can either be strong or weak.
In general you should make your outlet strong, especially if you are connecting an outlet to a sub view or to a constraint that's not always going to be retained by the view hierarchy.
The only time you really need to make an outlet weak is if you have a custom view that references something back up the view hierarchy and in general that's not recommended.
So I'm going to choose strong and I will click connect which will generate my outlet.
In iOS development NIB loading is a little bit different from Mac development.
In Mac development an IBOutlet is usually a weak reference: if you have a subclass of NSViewController only the top-level view will be retained and when you dealloc the controller all its subviews and outlets are freed automatically.
UiViewController use Key Value Coding to set the outlets using strong references. So when you dealloc your UIViewController, the top view will automatically deallocated, but you must also deallocate all its outlets in the dealloc method.
In this post from the Big Nerd Ranch, they cover this topic and also explain why using a strong reference in IBOutlet is not a good choice (even if it is recommended by Apple in this case).
One thing I wish to point out here, and that is, despite what the Apple engineers have stated in their own WWDC 2015 video here:
https://developer.apple.com/videos/play/wwdc2015/407/
Apple keeps changing their mind on the subject, which tells us that there is no single right answer to this question. To show that even Apple engineers are split on this subject, take a look at Apple's most recent
sample code, and you'll see some people use weak, and some don't.
This Apple Pay example uses weak:
https://developer.apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_swift.html#//apple_ref/doc/uid/TP40016175-Emporium_ProductTableViewController_swift-DontLinkElementID_8
As does this picture-in-picture example:
https://developer.apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_swift.html#//apple_ref/doc/uid/TP40016166-AVFoundationPiPPlayer_PlayerViewController_swift-DontLinkElementID_4
As does the Lister example:
https://developer.apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_swift.html#//apple_ref/doc/uid/TP40014701-Lister_ListCell_swift-DontLinkElementID_57
As does the Core Location example:
https://developer.apple.com/library/ios/samplecode/PotLoc/Listings/Potloc_PotlocViewController_swift.html#//apple_ref/doc/uid/TP40016176-Potloc_PotlocViewController_swift-DontLinkElementID_6
As does the view controller previewing example:
https://developer.apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546-Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift-DontLinkElementID_5
As does the HomeKit example:
https://developer.apple.com/library/ios/samplecode/HomeKitCatalog/Listings/HMCatalog_Homes_Action_Sets_ActionSetViewController_swift.html#//apple_ref/doc/uid/TP40015048-HMCatalog_Homes_Action_Sets_ActionSetViewController_swift-DontLinkElementID_23
All those are fully updated for iOS 9, and all use weak outlets. From this we learn that A. The issue is not as simple as some people make it out to be. B. Apple has changed their mind repeatedly, and C. You can use whatever makes you happy :)
Special thanks to Paul Hudson (author of www.hackingwithsift.com) who gave me the clarification, and references for this answer.
I hope this clarifies the subject a bit better!
Take care.
From WWDC 2015 there is a session on Implementing UI Designs in Interface Builder. Around the 32min mark he says that you always want to make your #IBOutlet strong.
Be aware, IBOutletCollection should be #property (strong, nonatomic).
It looks like something has changed over the years and now Apple recommends to use strong in general. The evidence on their WWDC session is in session 407 - Implementing UI Designs in Interface Builder and starts at 32:30. My note from what he says is (almost, if not exactly, quoting him):
outlet connections in general should be strong especially if we connect a subview or constraint that is not always retained by the
view hierarchy
weak outlet connection might be needed when creating custom views that has some reference to something back up in the view hierarchy
and in general it is not recommended
In other wards it should be always strong now as long as some of our custom view doesn't create a retain cycle with some of the view up in the view hierarchy
EDIT :
Some may ask the question. Does keeping it with a strong reference doesn't create a retain cycle as the root view controller and the owning view keeps the reference to it? Or why that changed happened?
I think the answer is earlier in this talk when they describe how the nibs are created from the xib. There is a separate nib created for a VC and for the view. I think this might be the reason why they change the recommendations. Still it would be nice to get a deeper explanation from Apple.
I think that most important information is:
Elements in xib are automatically in subviews of view. Subviews is NSArray. NSArray owns it's elements. etc have strong pointers on them. So in most cases you don't want to create another strong pointer (IBOutlet)
And with ARC you don't need to do anything in viewDidUnload
I'm encountering a strange situation with NSWindowController. I want the window controller to be released but it will not. It doesn't seem to be following my expectations for ARC behavior.
I've created a simple window controller subclass, PlainWindowController. Its interface and implementation are empty:
#import <Cocoa/Cocoa.h>
#interface PlainWindowController : NSWindowController
#end
#implementation PlainWindowController
#end
I created with it a default windowController xib named PlainWindowController.xib, which has a window with delegate and windowController connections already set.
In a test, I've written this code:
PlainWindowController *strongWindowController = [[PlainWindowController alloc] initWithWindowNibName:#"PlainWindowController"];
__weak PlainWindowController *weakWindowController = strongWindowController;
[strongWindowController showWindow:nil];
strongWindowController = nil;
STAssertNil(weakWindowController, #"The window controller should have been deleted, wasn't");
When this test runs, the weak reference is not nil.
If I leave out the showWindow it is nil. If I use init instead of initWithWindowNibName, it is nil.
Does anyone know what's going on here? Thank you in advance for any guidance.
There’s no guarantee that an object under ARC hasn’t been added to the autorelease pool, in which case it won’t be freed until the end of the current event.
In your case, I strongly suspect somewhere within initWithWindowNibName: the controller gets retained and autoreleased.
If you really want to ensure your object is being freed, just subclass the -dealloc method and add an NSLog to it or break on it.
You generally shouldn't harbor "expectations" about when objects are deallocated if they've ever been passed to other code which you don't control.
Cocoa might have retained and then autoreleased the controller. Cocoa may retain the window controllers of any windows which are showing.
In general, when it comes to Cocoa memory management, you are supposed to make sure your own code follows the rules (which ARC largely does for you) and you should assume that other code follows the rules, but you can't assume that other code doesn't retain objects beyond where your interest ends. You should basically not care about what the other code is doing with respect to memory management.
If you really want to know what's happening, run your app under the Allocations instrument and explore the retain/release/autorelease history of your object after the point where you expected it to have been deallocated.
I had a similar issue when first using ARC. I unfortunately don't remember the details as this was more than a year ago. I eventually tracked it down as a circular retain problem using Instruments to monitor retain values, although not without losing a lot of hair.
I think the actual problem was with the delegate which I fixed with #property (unsafe_unretained) id delegate;
I ran into a similar issue yesterday with an ARC based project - a NSWindowController subclass would not deallocate, nor did -dealloc fire. I worked with Zombies, Allocations to no avail. The problem was very simple. There was a subclassed control within the window, and in that controls subclass .h header file a property was defined as:
#property id delegate;
correcting it to
#property (nonatomic, weak) id delegate;
fixed the issue.
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
I'm studying memory managment in UIviewController, i'm a little confused, the important points to remember are:
viewDidLoad is called every time the view is shown, here I alloc variables of any kind.
viewDidUnload is called in case of low memory, I set all the property to nil.
dealloc, I release all property.
Is it all right?
Also, if I don't link a label to a IBOutlet, have I a memory leak or the system dealloc it anyway?
No. -viewDidLoad is called when the controller loads its view, not every time the view is displayed. Perhaps you're thinking of -viewWillAppear. Otherwise, your points are about right.
If you don't connect something to an outlet, the outlet will simply remain nil -- there's no leak. The label will generally be retained by its enclosing view, and will be released when the rest of the view hierarchy is released.
I'm creating one Cocoa application for myself and I found a problem. I have two NSTextFields and they're connected to each other as nextKeyViews. When I run this app with memory leaks detection tool and tab through those 2 textboxes for a while, enter some text etc., I start to leak memory. It shows me that the AppKit library is responsible, the leaked objects are NSCFStrings and the responsible frames are [NSEvent charactersIgnoringModifiers] and [NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]. I know this is quite a brief and incomplete description, but does anyone have any ideas what could be the problem?
Also, I don't use GC, so I release my instance variables in the controllers dealloc. What about the outlets? Since IBOutlet is just a mark for Interface Builder and doesn't actually mean anything, should I release them too?
What about the outlets? Since IBOutlet is just a mark for Interface Builder and doesn't actually mean anything, should I release them too?
Your declaration of the IBOutlet tells you how to manage it... If you declare it as retained and then #synthesize it, the process of loading the nib will retain the outlet. Therefore you must release it.
Andiih coined the mnemonic NARC
NARC: "New Alloc Retain Copy". If you
are not doing any of those things, you
don't need to release.
The corollary is also true.. if you do any of those, you are responsible for releasing the object at the appropriate time.