I looked up this topic on google but have not got an understandable answer yet, the problem is that I know that when two classes are coupled together by instantiating an object in the first class from the second class and declaring another object in the second class from the first class this will cause a retain cycle that should be broken by using the keyword weak or unowned , yet I can not apply this way of thinking on the IBOutlets being declared as weak
for example
class SignUpViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var signUpBttn: UIButton!
}
this is an outlet in my viewController class, why the outlet is declared as weak ? as per what I understand is that to have a retain cycle, the uibutton class should have an object from the viewController class so that the two classes (viewController and uibutton) become coupled together
can anybody clarify what is happening under the hood?
all ui element in a view controller are part of the viewController view. so view is a UIView class and outlets are reference in the viewController to UIView class elements, so if the view is removed form the view hierarchy all cross element should be weak to avoid cross reference. thew eid problem about this is the reference from apple MVC, where a ViewController is a Controller but have a bunch o related code of the view part. all you outlets should be placed in the UIView class of you ViewController.
TLDR - in my opinion it's not a good decision.
A strong reference denotes ownership. The view or view controller is the owner of the views therefore the logical choice should be strong.
However, in most situations this does not really matter because the views are also strongly referenced by their parent in the view hierarchy.
When does it matter? It matters in situations when you are dynamically updating the view hierarchy by removing views/constraints etc. Once you remove a view/constraint from the hierarchy and you don't have a strong reference to it, it will get removed from memory.
Also note that the combination of weak and ! is a bit dangerous because ! denotes a reference that you expect never to be nil.
This can lead to errors, for example:
#IBOutlet weak var constraint: NSLayoutConstraint!
...
constraint.isActive = false // removes constraint from hierarchy, assigns `nil` to constraint
...
constraint.isActive = true // crashes the app
Personally, I always make outlets strong. For any weak references I always use ? and not !.
Note that weak in this case doesn't have anything to do with protection against reference cycles. It was just a personal decision by Xcode developers.
Historically, there might be a connection with UIViewController.viewDidUnload. However, that method is never called since iOS 6.
Apple recommends that an #IBOutlet be declared as strong. Many discussions / articles can be found about this.
If you take a look at this video from Apple's 2015 WWDC, right around the 32:30 mark: https://developer.apple.com/videos/play/wwdc2015/407/
He states:
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.
I'm following a tutorial on Swift and I noticed that the author uses var instead of let when declaring an #IBOutlet variable. So I became curious as to why I can't use let instead since an object's properties are still mutable even if the object is constant or is this not the case?
The error Xcode shows when using let is
#IBOutlet attribute requires property to be mutable
but I'm confused because questionLabel is a UILabel object and not necessarily a property of an object. Or is the questionLabel object a property of the current viewController?
import UIKit
class ViewController: UIViewController {
#IBOutlet let questionLabel: UILabel!
}
Thank you in advance if I'm over analyzing.
The #IBOulet marked properties are generally properties of a ViewController that are connected using the interface builder. The view you create in the interface builder has to actually connect the interface elements in it to the properties during your actual application runtime.
For that reason it firstly creates a new ViewController using some init without connecting any interface elements. They only get connected at a later stage. For the runtime to be able to hook the properties up to the view elements after the object creation has completed they cannot be constants, they have to be mutable. Because they do not have a value after the initializer has finished they have to be optionals. And to not make using the properties cumbersome afterwards they are implicitly unwrapped optionals, so that you do not have to write label!.property but label.property suffices.
That is why your code crashes as soon as you try to do something with an IBOutlet variable which you failed to connect and that is also the reason why you cannot use / change / manipulate those fields in the initializer.
Regarding your actual var / let confusion. Yes, the object itself that is referenced using let can be changed, e.g. the text of a UILabel BUT the actual object reference cannot be changed. That would mean that if you do not give the constant a specific value in the initializer it would forever remain nil.
For the simple reason that it is not assigned during initialization (in the initXXX methods) but later, when the view is being loaded.
The compiler actually cannot be even sure that the variable is ever assigned because the view loading is comletely dynamic.
In swift, all vars and lets can be thought of as properties.
A property is immutable (a constant) if it's declared with let. It's mutable (a variable) if it's declared using the var keyword. That is the defining difference between let and var.
Outlets must be mutable because their value does not get set until after the object is initialized. (The view controller gets initialized and it's outlets don't get loaded right away.)
You are right questionLabel is an object of type UILabel but used as a property of your class ViewController. That's why you have #IBOutlet attribute requires property to be mutable. If you use var you are saying that a property is mutable. If you use let you are saying that the property is immutable.
Try to create questionLabel without #IBOutletand see what's going on. Probably, you can put let in front.
First the ViewController is created, then the view tree is built. That means that when the ViewController finished it's init these views don't exist yet. They will be added just before viewDidLoad by parsing the XML-like data of the storyboard or XIB.
I know that it's Apple's default way of doing things but I would always write my outlets like:
#IBOutlet let questionLabel: UILabel?
For the simple reason it's absolutely not proven this label will really exist at run time. For example when reusing ViewControllers over multiple screens, changing the layout after setting the connections and so on this outlet might not be set. If you would use the questionLabel defined as UILabel! and it would be nil your application will crash. I don't think applications in production should ever crash over something silly like that.
For real application safety the only way to know really for sure it exists is to build your UI's in code. But the ease of use of Storyboards for one off screens is really tempting, I still use them a lot.
When I create a label in the view (dragged from the Object library) and make the IBOutlet to connect the label and viewController (Ctrl and drag), The default code generated by Xcode is, for example, #IBOutlet weak var displayColumn: UILabel!
I can delete the exclamation mark and set it as the UILable only. But there must be a good reason the Xcode want it to be a forced unwrapped optional type.
Question: I don't think I understand the reason to use the optional type here. Because I already created a label in my view and connected it to my controller, it is firmly out there, it exists, I created it. Why Xcode want an option as the default type? If it says the text inside the label is an option, that sounds reasonable to me, because the label may be empty at some point in run time.
Many Thanks
You have created a label in Xcode and indicated to Xcode that you want that label connected to that #IBOutlet. But that connection doesn't happen until later.
This is the order of events at runtime.
The viewController is created (instantiated).
The Storyboard or .xib is unarchived. The label is created at this time.
The #IBOutlets and #IBActions are connected.
In Swift, when a class is instantiated, all properties must be initialized. In step 1, the outlets are nil because they haven't been connected yet. In order to allow for this, they must be declared as Optionals.
It is perfectly valid to use a normal Optional, such as:
#IBOutlet weak var displayColumn: UILabel?
but then you'd have to deal with unwrapping it each time you access it. The only time an #IBOutlet will be nil is when step 3 hasn't happened yet (for example, in prepareForSegue) or if you forgot to connect the outlet or renamed it. In those cases, the crash caused by accessing nil alerts you to the problem.
Looking at this,
#IBOutlet weak var label1 : UILabel!
Why is UILabel an optional? The fact that I established a IBOutlet connection to that UILabel means that the UILabel DEFINATELY exists, and wouldn't be nil. So why is it an optional UIlabel? and not UILabel?
It's becouse non-optional variables have to be initialized in constructor and leave all lifecicle.
IBOutlets are weak also, what means it can become nil while e.g. view contoller are still alive.
This is about how The View Controller life cycle actually works into play.
Let's be known of Model, View, and Controllers, before proceeding.
The View Controller object itself gets instantiated before the view is loaded i.e. your label. During this time, since view is not even loaded, there is no reference to the label, as it still needs to be created from storyboard.
For this reason, the object becomes nil for a pretty short unnoticable moment. And, when the view is loaded: ViewController, viewDidLoad(), then only the labels reference is assigned to the variable.
This outlines a short description on why optionals are really used in iOS.
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