Should IBOutlets be strong or weak under ARC?
Asked Answered
F

11

574

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.

Foolhardy answered 6/10, 2011 at 17:56 Comment(3)
As a note, IBOutletCollection() must not be weak, otherwise it returns as nil.Bogbean
Xcode 8.2.1 uses weak when creating IBOutlets via interface builder. However many answers here on SO advises to use strong.Unbidden
@Unbidden I just tried with xcode 8.3.2 dragging from storyboard to swift file and it defaults to strongMaybellmaybelle
P
291

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

Periclean answered 14/7, 2015 at 0:59 Comment(13)
Is this really true or is the answer with 300+ upvotes the correct one? I noticed that InterfaceBuilder by default uses weak when you Ctrl-drag from the storyboard to the .hNonparous
The one with 400+ votes is correct, but outdated. Since iOS 6 viewDidUnload doesn't get called, so there are no benefits for having weak outlets.Albertson
@Albertson there are benefits. First and foremost you shouldn't hold a strong reference to something you didn't create. Second, the performance gain is negligible. Don't violate best practices in programming simply because some guy, even a well placed guy, said this is 10 microseconds faster. Code clear intent, don't try to play optimizing compiler. Only code for performance when it has been measured in a specific case to be a problem.Lithe
Let me disagree with you. 'Holding a strong reference to something you didn't create' happens all the time in Objective-C. That's why there is a reference counting, rather then a single owner. Do you have any references to back-up this recommendation? Could you pls list the other benefits of weak outlets?Albertson
Here is the WWDC video mentioned in the answer developer.apple.com/videos/play/wwdc2015/407/?time=1946Quetzal
“Is this really true or is the answer with [more] upvotes the correct one?” isn’t really a valid question, when this answer cites an Apple engineer as its source. You can consider what Apple says about Apple’s API usage to be correct by definition.Plead
@ChrisHanson Almost 3 years later Apple's docs still state that they should be weak though "except for those from File’s Owner to top-level objects". So do we trust the docs or the engineer?Toxicology
This answer just says "do this" and doesn't explain anything. If I need weak references sometimes, and at other times it doesn't matter, why would I ever use strong references? I don't care who posts this information, it has to be explained, otherwise it is just someone's opinion.Ruelle
It's odd that Ctrl-dragging to .h files still creates weak (as of XCode 10) if this is not recommended. I have no issues with this though. Everything works. It's quite confusing.Annunciation
I disagree that. The IBOutlets should be declared weak. Creating strong references wont allow views to deallocate. Its a good practice but can be a personal preference for those who know what they are doing. Eg create a strong reference to a nested subview in controller and removing its parent view would not deallocate the memory because its strong. Even better make outlets optional instead of implicitly unwrapped to avoid crashes.Agretha
So who is correct? Xcode 12 use weak as default option when creating IBOutlets.Delinquent
Xcode 14 uses weak by default when creating IBOutlets. I don't think that the source of truth has to come from a 7 years old declaration from a single engineer (Kevin Cathey) that wasn't backed by a written documentation or an Xcode behaviour. We should ask Apple to clarify why Kevin's recommendation doesn't match the doc and Xcode.Frater
Xib and file can make a retain cycle with strong outlets. In my practice I needed to make strong outlets only for constraints, in case it can be temporarily disabled. Without strong it would be deallocated. Otherwise the xib hold the reference and file don't need to hold it too.Jadwiga
S
454

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;
    
Saul answered 11/10, 2011 at 16:10 Comment(17)
How did you get the "developer library" link to jump to the particular part of the apple doc page? Whenever I link to the apple docs it always links to the top of the page (even if the content of interest is halfway down the page). Thanks.Augustaaugustan
I copied the link from the navigation pane on the left. :DSaul
What does "except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene)" mean?Gripper
@VanDuTran - it means objects in the NIB that are at the root level, i.e. say you instantiated another view in there which isn't directly a subview of the main view, then it needs to have a strong reference.Hydrolyze
Yes, but you haven't directly answered the question.Eigenfunction
If that is the case, then why is it when you choose "weak" from the drag-and-drop Referencing Outlets, Xcode automatically fills it in as "unsafe_unretained"? Which is correct?Maguire
Top level means that when you look at the nib, the object appears in the list on the left. Almost all nibs have a UIView in them - this might be the only top level object. If you add other items, and they show in the list, they are "top level objects"Martica
So we still need to do topLevelObject=nil at viewDidUnload? Otherwise none of those subclasses will be deallocated then given that topLevelObject still have references to all of them.Merganser
@Maguire unsafe_unretained is what it'll produce if your project targets a version of iOS that's older than 5, but still supports ARC. If it targets only 5 or up, it'll give you weak instead.Hebraism
@JimThio, I want to know the answer to your question too. Should we set the strong topLevelObject to nil on viewDidUnload?Quartz
Is there any real world cases where using strong/retained for your IBOutlet could cause problem? Or is it just a redundant retain, which means bad coding style but wouldn't affect your code?Reminiscent
@EnzoTran, if you set the IBOutlet to be strong(same as retain), then your outlets will have a second owner (the viewcontroller) other than the view that retained it already. So you have to release the memory used by that outlet in viewcontroller's viewDidUnload.Jambalaya
@Jingjie Zhan: true, except that viewDidUnload is no longer called since iOS 6.Reminiscent
@AlexsanderAkers hi, i know you did a good job explaining this.. but could you help me with this related question? I understand diagrams better than words --> #18969638Briefcase
Good article on NSHipster on the topic: nshipster.com/ibaction-iboutlet-iboutletcollectionCarreno
Top level object of view controller in storyboard will be stored in an array: _topLevelObjectsToKeepAliveFromStoryboard, but not for xib file, so top level objects' outlets could be weak if you're using storyboard.Christoffer
This looks like it is no longer true and the docs are in the process of being updated. - twitter.com/_danielhall/status/620716996326350848 - twitter.com/_danielhall/status/620717252216623104Periclean
P
291

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

Periclean answered 14/7, 2015 at 0:59 Comment(13)
Is this really true or is the answer with 300+ upvotes the correct one? I noticed that InterfaceBuilder by default uses weak when you Ctrl-drag from the storyboard to the .hNonparous
The one with 400+ votes is correct, but outdated. Since iOS 6 viewDidUnload doesn't get called, so there are no benefits for having weak outlets.Albertson
@Albertson there are benefits. First and foremost you shouldn't hold a strong reference to something you didn't create. Second, the performance gain is negligible. Don't violate best practices in programming simply because some guy, even a well placed guy, said this is 10 microseconds faster. Code clear intent, don't try to play optimizing compiler. Only code for performance when it has been measured in a specific case to be a problem.Lithe
Let me disagree with you. 'Holding a strong reference to something you didn't create' happens all the time in Objective-C. That's why there is a reference counting, rather then a single owner. Do you have any references to back-up this recommendation? Could you pls list the other benefits of weak outlets?Albertson
Here is the WWDC video mentioned in the answer developer.apple.com/videos/play/wwdc2015/407/?time=1946Quetzal
“Is this really true or is the answer with [more] upvotes the correct one?” isn’t really a valid question, when this answer cites an Apple engineer as its source. You can consider what Apple says about Apple’s API usage to be correct by definition.Plead
@ChrisHanson Almost 3 years later Apple's docs still state that they should be weak though "except for those from File’s Owner to top-level objects". So do we trust the docs or the engineer?Toxicology
This answer just says "do this" and doesn't explain anything. If I need weak references sometimes, and at other times it doesn't matter, why would I ever use strong references? I don't care who posts this information, it has to be explained, otherwise it is just someone's opinion.Ruelle
It's odd that Ctrl-dragging to .h files still creates weak (as of XCode 10) if this is not recommended. I have no issues with this though. Everything works. It's quite confusing.Annunciation
I disagree that. The IBOutlets should be declared weak. Creating strong references wont allow views to deallocate. Its a good practice but can be a personal preference for those who know what they are doing. Eg create a strong reference to a nested subview in controller and removing its parent view would not deallocate the memory because its strong. Even better make outlets optional instead of implicitly unwrapped to avoid crashes.Agretha
So who is correct? Xcode 12 use weak as default option when creating IBOutlets.Delinquent
Xcode 14 uses weak by default when creating IBOutlets. I don't think that the source of truth has to come from a 7 years old declaration from a single engineer (Kevin Cathey) that wasn't backed by a written documentation or an Xcode behaviour. We should ask Apple to clarify why Kevin's recommendation doesn't match the doc and Xcode.Frater
Xib and file can make a retain cycle with strong outlets. In my practice I needed to make strong outlets only for constraints, in case it can be temporarily disabled. Without strong it would be deallocated. Otherwise the xib hold the reference and file don't need to hold it too.Jadwiga
B
52

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. ;)

Brochu answered 10/12, 2013 at 21:54 Comment(8)
That is true, but you may still want to unload the view yourself. In which case you'd have to set all of your outlets to nil manually.Foolhardy
PS: weak is a quite a bit cheaper in ARM64 :DFoolhardy
That's right, if you implement view unloading, weak properties or __weak instance variables are the way to go. I just wanted to point out that there is less potential for error here. As for weak being cheaper on arm64, I have not even seen a real-life performance problem with weak IBOutlets on armv7. :)Brochu
In that case, strong makes sense as well. strong is only harmful if you use view unloading—but who does these days? :)Brochu
What would you say about this situation? SO: Objective C: GestureRecognizer in ViewController --> retain cycleAcapulco
@Acapulco See my answer there. It's not a problem since gesture recognizers don't keep strong references to targets/delegates. :)Brochu
Why would you want to use viewUnloading?Venery
@Rocotilos The first iPhone had very limited RAM. If I recall correctly, 128 MB, leaving around 10 MB for the active app. Having a small memory footprint was crucial, hence there was view unloading. That changed as we now have more and more RAM, and Apple optimized UIViews in iOS 6, so that on memory warnings, a lot of memory can be freed without unloading the view.Brochu
L
34

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.

Labellum answered 7/10, 2011 at 22:34 Comment(3)
It is also my understanding that weak properties do not need to be nilled in viewDidUnload. But why does Apple’s template for creating outlets include a [self setMySubview:nil]?Cord
Is there any real world cases where using strong/retained for your IBOutlet could cause problem? Or is it just a redundant retain, which means bad coding style but wouldn't affect your code?Reminiscent
Is there such a thing as a redundant retain? If there's an extra retain, that will cause it to not be counted properly, and therefore won't be freed as soon as it could be since there's an extra retain on its retain count.Haihaida
A
27

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.

Affectation answered 4/11, 2015 at 4:27 Comment(6)
Great answer that explains the actual reason -why-Abarca
That is good and all but i have seen leaks coming from gesture recognizers implemented in storyboard.Inkerman
I can't understand this line. "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." Any examples?Aruwimi
I calculated the deinit time that weak and strong takes , and it's exactly the same.Upu
But in swift this is more the case. Weak references are faster.Recce
@thesummersign I don't see a difference when I time weak for strong in swift..Voracious
P
19

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).

Papaw answered 10/10, 2011 at 16:2 Comment(3)
It explains it as at 2009. With ARC, this has changed significantly.Hebraism
:( the Big Nerd Ranch link is dead… yet I really need to read it. Anyone knows more details about that post, so I can find it?Gearldinegearshift
@MottiShneor don't worry, it's no big deal since the link was about times before ARC and is not relevant anymore.Hearts
S
18

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.

Seagoing answered 5/5, 2016 at 21:25 Comment(1)
I have been checking on this issue for sometime and haven't found any concrete answers. Since the above link suggests that both are fine and in general go with what Xcode autosuggests.Newsy
L
10

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.

Lobate answered 9/7, 2015 at 13:11 Comment(1)
Interesting. I guess this changed when view unloading was removed?Foolhardy
K
6

Be aware, IBOutletCollection should be @property (strong, nonatomic).

Kibitka answered 25/3, 2014 at 13:2 Comment(1)
Why not copy as it is an NSArray?Foolhardy
B
5

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.

Brunildabruning answered 7/8, 2015 at 8:28 Comment(0)
L
4

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

Likeminded answered 4/12, 2012 at 14:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.