I am working on an application where I need to be able to change the same .property
for multiple UI objects to similar values at the same time.
As a SO-friendly example to illustrate my question, suppose you have 3 UILabels named label1
, label2
, and label3
that are being imported from an external .xib
file, so they're each declared as @IBOutlet
at the top of the VC. When you set up the labels and drag the outlets to the VC, XCode helpfully adds the declarations to the code for you, including the !-bang to implicitly unwrap the UILabel conditional.
@IBOutlet weak var label1: UILabel!
@IBOutlet weak var label2: UILabel!
@IBOutlet weak var label3: UILabel!
Now suppose you want to change the .text
property of each to a new value called newValue
:
let newValue = "This is Label #"
label1.text = newValue + "1"
label2.text = newValue + "2"
label3.text = newValue + "3"
returns:
This is Label #1
This is Label #2
This is Label #3
Straightforward enough, but not very DRY. In production I will have much longer groups of labels to update, so I'd like to simplify this.
Here's where it gets weird. Try expressing the same 3 statements in a for-in loop:
let labelArray = [label1, label2, label3]
for i in 0...2 {
labelArray[i].text = newValue + "\(i+1)"
The above code will throw a compiler error:
--> Value of optional type 'UILabel?' must be unwrapped
to refer to member 'text' of unwrapped base type 'UILabel'
I can certainly fix the code to satisfy the compiler -- that's not my question. For one, adding a !
to the labelArray[i]
statement will dismiss the error:
labelArray[i]!.text = newValue + "\(i+1)"
But the question is -- why is this necessary? One, aren't the UILabel conditionals already implicitly unwrapped in the @IBOutlet
statement, and two, why does setting the .text
property one at a time, each in a separate statement, not throw the same compile error? What's different?
Full code:
import UIKit
class ViewController: UIViewController{
// Outlet Declarations for UILabels
@IBOutlet weak var label1: UILabel!
@IBOutlet weak var label2: UILabel!
@IBOutlet weak var label3: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let newValue = "This is Label #"
// This method doesn't throw an unwrap error
label1.text = newValue + "1"
label2.text = newValue + "2"
label3.text = newValue + "3"
// This method throws an unwrap error
let labelArray = [label1, label2, label3]
for i in 0...2 {
labelArray[i].text = newValue + "\(i+1)"
}
}
}