使用 Computed variable 和 Snapkit 时:视图之间没有通用的超级视图
When using Computed variable and Snapkit: No common superview between views
事情是这样的,我要这样声明 属性:
var aNameLabel: UILabel {
guard let foo = Applicant.sharedInstance.realName else {
return UILabel(text: "获取姓名失败", color: .whiteColor())
}
return UILabel(text: foo, color: .whiteColor())
}
当我在 someView.addSubView(aNameLabel)
之后尝试向 aNameLabel 添加约束时,应用程序每次都会在这个添加约束的地方崩溃,并显示 No common superview between views
但是,当我像这样将变量更改为 let 常量时:
let aNameLabel = UILabel(text: "Allen", color: .whiteColor())
将在没有投诉的情况下添加约束。有人可以帮我解决这个问题吗?
更新
在@par 的帮助下,我将代码更改为:
var aNameLabel: UILabel = {
guard let foo = Applicant.sharedInstance.realName else {
return UILabel(text: "BAD", color: .whiteColor())
}
return UILabel(text: foo, color: .whiteColor())
}()
然后 aNameLabel
总是被赋值为“BAD”,而实际上我的 guard let
是成功的。我该如何解决这个问题?
问题是您每次访问 aNameLabel
变量时都会创建一个新的 UILabel
(计算的 属性 函数在您每次访问它时都会运行)。大概您正在为此视图的超级视图做同样的事情(当您在上面的示例中访问 someView.addSubview()
中的 someView
时)。如果是这样,那就是为什么没有通用的超级视图而你崩溃了。
您应该只为您的视图控制器使用的每个 UIView
创建一个实例,因此创建一个变量作为常量,如您所展示的 是 一个很好的方法,或者您可以使用像这样的闭包初始化器模式:
var aNameLabel: UILabel = {
return UILabel(...)
}()
注意上例中右大括号后的括号。因为它是一个闭包初始化器,所以它只会被调用一次,就像 let
常量一样。
通常使用 let
创建的 UIView
是不合适的,因为常量属性需要在 init()
returns 之前初始化,并且如果您正在创建视图一个视图控制器,在调用 loadView()
之前,您将没有机会添加视图。在这种情况下,将您的 UIView
声明为隐式展开的可选值。它们会被init()
设置为nil
,满足初始化要求,之后调用viewDidLoad()
时可以设置为实际视图,例如:
class MyViewController: UIViewController {
var someSubview: UIView!
override func viewDidLoad() {
super.viewDidLoad()
someSubview = UIView()
view.addSubview(someSubview)
// now set constraints with SnapKit
}
}
事情是这样的,我要这样声明 属性:
var aNameLabel: UILabel {
guard let foo = Applicant.sharedInstance.realName else {
return UILabel(text: "获取姓名失败", color: .whiteColor())
}
return UILabel(text: foo, color: .whiteColor())
}
当我在 someView.addSubView(aNameLabel)
之后尝试向 aNameLabel 添加约束时,应用程序每次都会在这个添加约束的地方崩溃,并显示 No common superview between views
但是,当我像这样将变量更改为 let 常量时:
let aNameLabel = UILabel(text: "Allen", color: .whiteColor())
将在没有投诉的情况下添加约束。有人可以帮我解决这个问题吗?
更新
在@par 的帮助下,我将代码更改为:
var aNameLabel: UILabel = {
guard let foo = Applicant.sharedInstance.realName else {
return UILabel(text: "BAD", color: .whiteColor())
}
return UILabel(text: foo, color: .whiteColor())
}()
然后 aNameLabel
总是被赋值为“BAD”,而实际上我的 guard let
是成功的。我该如何解决这个问题?
问题是您每次访问 aNameLabel
变量时都会创建一个新的 UILabel
(计算的 属性 函数在您每次访问它时都会运行)。大概您正在为此视图的超级视图做同样的事情(当您在上面的示例中访问 someView.addSubview()
中的 someView
时)。如果是这样,那就是为什么没有通用的超级视图而你崩溃了。
您应该只为您的视图控制器使用的每个 UIView
创建一个实例,因此创建一个变量作为常量,如您所展示的 是 一个很好的方法,或者您可以使用像这样的闭包初始化器模式:
var aNameLabel: UILabel = {
return UILabel(...)
}()
注意上例中右大括号后的括号。因为它是一个闭包初始化器,所以它只会被调用一次,就像 let
常量一样。
通常使用 let
创建的 UIView
是不合适的,因为常量属性需要在 init()
returns 之前初始化,并且如果您正在创建视图一个视图控制器,在调用 loadView()
之前,您将没有机会添加视图。在这种情况下,将您的 UIView
声明为隐式展开的可选值。它们会被init()
设置为nil
,满足初始化要求,之后调用viewDidLoad()
时可以设置为实际视图,例如:
class MyViewController: UIViewController {
var someSubview: UIView!
override func viewDidLoad() {
super.viewDidLoad()
someSubview = UIView()
view.addSubview(someSubview)
// now set constraints with SnapKit
}
}