1

I notice when I'm writing in Swift, if I declare a label in the ViewController as either var label: UILabel! or var label = UILabel(), and then initialize them in the viewDidLoad method, they both seem to, functionally, work identically. So what is the difference between these two?

On a related note, when I declare var label: UILabel! I have to write label = UILabel(frame:CGRectMake(...)), but if I use var label = UILabel() I have to write label.frame = CGRectMake(...). Is this because var label = UILabel() is both declaring and instantiating a class object whereas var label: UILabel! is simply declaring a variable of a type? I'm confused about what's actually going on here.

Thanks in advance!

Bryan Chapel
  • 346
  • 2
  • 12
  • You can write `var label: UILabel! = UILabel()`, no? What does this mean (esp. in terms of having to set the frame later)? Look up [Type Inference](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID457) for the case when there is no explicit type - eg. with ":" - specified. – user2864740 Feb 26 '15 at 04:03
  • So `var label: UILabel!` is setting a variable named label with a type of UILabel, `var label = UILabel()` is creating a class instance and simply inferring the UILabel type (which is why `: UILabel!` isn't needed)? `var label = UILabel()` is `var label: UILabel! = UILabel()`, just shorthanded due to type inference? – Bryan Chapel Feb 26 '15 at 04:10
  • Yes. Type inference is central to Swift. This is no more surprising than `var x = 3` inferring x as an `Int`. – BaseZen Feb 26 '15 at 04:14
  • I think my brain was verging on realizing that before I got in the way. Thanks BaseZen! A real /headdesk moment for me. – Bryan Chapel Feb 26 '15 at 04:20

2 Answers2

2
var label: UILabel!

is declaring that you have a UILabel variable that may be empty (Optional), but you can access it pretending as if it will not - usually that means it would be an IBOutlet that would be set by the interface storyboard on load, before you tried to use the label.

var label = UILabel()

is declaring that you have a label that will always hold a label, and can never be nil. It is ALSO creating an instance of a UILabel when a class instance is created, even though you say you assign a different label to the variable in viewDidLoad()

There's no difference in access, but it does mean no matter when you use that variable it will hold a real value and not be nil.

They both are variables of type UILabel.

I'm not sure why you could not not set the variable to a new UILabel using the CGRect constructor, that should be possible. Perhaps at one point you had said let label = UILabel(), which would mean it was a fixed variable that could not hold a new value - so all you could do was alter the frame of the variable that exists already.

The best approach for something like what you are doing is to declare the variable an Optional:

 var label : UILabel?

Which makes it an true Optional, and makes sure that you do not accidentally write code that accesses the variable badly if it's never been set, or sets a value to your first label before you assign the "real" UILabel in your viewDidLoad method. Accessing is a little different, but not much harder - to set text you just use the "?" syntax to optionally call the property if the instance has been set:

label?.text = "fred"
Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
  • 1
    "I'm not sure why you could not not set the variable to a new UILabel using the CGRect constructor, that should be possible." Me either, I think that was the real root of my confusion. – Bryan Chapel Feb 26 '15 at 04:12
  • Just added a thought as to what might be happening. – Kendall Helmstetter Gelner Feb 26 '15 at 04:15
  • That makes a lot of sense. I think at one point I was toying around with lets and vars in my declarations just to see what would happen. Could have been a remnant of my code from those tests. Thanks! – Bryan Chapel Feb 26 '15 at 04:18
  • One last follow up question: Which of these declarations would be considered "Best Practice"? I'd like to improve my standards going forward. Thanks again! – Bryan Chapel Feb 26 '15 at 04:23
  • Best practice in Swift would (in my opinion) to use the var label : UILabel?. Next would be var label : UILabel! (which is what Interface Builder creates by default) but only if you are really, really sure nothing will access a label before viewDidLoad() is called (very easy to make a view controller instance and access properties before the view is accessed). Last would be var label = UILabel(), mostly because it's making two instances of labels (though you could switch to let label = UILabel() and just use the one instance, but it would seem "weird" to others I think). – Kendall Helmstetter Gelner Feb 26 '15 at 04:39
2

You are correct. UILabel() calls the UILabel no-arg constructor and assigns that object reference to the label variable. So that's a declaration and an initialization.

In the case of the constructor, label is not an optional and is inferred to be the straightforward UILabel type, but in the case of your declaration label is an Optional type. The ! just means it's an optional with a force-unwrapping, so that when you use it as a value, you don't have to type the !; however if you declare it as force-unwrapped and you use it when it's nil-valued, your program crashes.

Note also that you're not allowed to declare:

var label: UILabel

as a class member unless you initialize it in all of your constructors, before the (possibly implicit) call to super.init() because it will complain that there is no initial value, so it might be referenced with no known value -- something the Swift compiler prevents.

BaseZen
  • 8,650
  • 3
  • 35
  • 47
  • "however if you declare it as force-unwrapped and you use it when it's nil-valued, your program crashes." Oh yeah, I've become very well acquainted with that one :) Thanks for the quick answer! – Bryan Chapel Feb 26 '15 at 04:15