So here's the thing, I'm declaring a property like this:
var aNameLabel: UILabel {
guard let foo = Applicant.sharedInstance.realName else {
return UILabel(text: "获取姓名失败", color: .whiteColor())
}
return UILabel(text: foo, color: .whiteColor())
}
And when I try to add constraint to the aNameLabel after I did someView.addSubView(aNameLabel)
, the app would crash every time at this constraint-adding thing, and says No common superview between views
However, when I change the variable into a let constant like this:
let aNameLabel = UILabel(text: "Allen", color: .whiteColor())
The constraint will be added with no complaint. Somebody can help me with this?
With the help of @par , I've changed my code into this:
var aNameLabel: UILabel = {
guard let foo = Applicant.sharedInstance.realName else {
return UILabel(text: "BAD", color: .whiteColor())
}
return UILabel(text: foo, color: .whiteColor())
}()
And then the aNameLabel
would always be assigned with value "BAD", while actually my guard let
is successful. How do I fix this?
The problem is that you are creating a new UILabel
every time you access the aNameLabel
variable (a computed property function runs every time you access it). Presumably you are doing the same thing for the superview of this view (when you access someView
in someView.addSubview()
in your example above). If so, that's why there's no common superview and you are crashing.
You should create only one instance of each UIView
used by your view controller, so creating a variable as a constant as you've shown is a great approach, or you can use a closure-initializer pattern like so:
var aNameLabel: UILabel = {
return UILabel(...)
}()
Notice in the above example the parentheses after the closing brace. Because it's a closure-initializer it will only be called once just like a let
constant.
Often a UIView
created with let
isn't appropriate because constant properties need to be initialized before init()
returns, and if you're creating views in a view controller you won't have a chance to add views until loadView()
is called. In this case, declare your UIView
s as implicitly-unwrapped optionals. They will be set to nil
by init()
which meets the initialization requirement, then you can set them to actual views later when viewDidLoad()
is called, for example:
class MyViewController: UIViewController {
var someSubview: UIView!
override func viewDidLoad() {
super.viewDidLoad()
someSubview = UIView()
view.addSubview(someSubview)
// now set constraints with SnapKit
}
}