使用 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
    }
}