При использовании переменной Computed и Snapkit: нет общего суперпредставления между представлениями

Так вот, я объявляю свойство как это:

var aNameLabel: UILabel {
    guard let foo = Applicant.sharedInstance.realName else {
        return UILabel(text: "获取姓名失败", color: .whiteColor())
    }
    return UILabel(text: foo, color: .whiteColor())
}

И когда я пытаюсь добавить ограничение в aNameLabel после того, как я сделал someView.addSubView(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 всегда будет присвоено значение "ПЛОХО", в то время как на самом деле мой guard let успешно. Как это исправить?

1 ответ

Решение

Проблема в том, что вы создаете новый UILabel каждый раз, когда вы получаете доступ к aNameLabel переменная (вычисляемая функция свойства запускается каждый раз, когда вы обращаетесь к ней). Предположительно, вы делаете то же самое для суперпредставления этого представления (когда вы someView в someView.addSubview() в вашем примере выше). Если так, вот почему нет общего супервизии и вы терпите крах.

Вы должны создать только один экземпляр каждого UIView используется вашим контроллером представления, поэтому создание переменной в качестве константы, как вы показали, является отличным подходом, или вы можете использовать шаблон closure-initializer следующим образом:

var aNameLabel: UILabel = {
    return UILabel(...)
}()

Обратите внимание, что в приведенном выше примере скобки после закрывающей скобки. Поскольку это инициализатор замыкания, он будет вызываться только один раз, как let постоянная.

Часто UIView создан с let не подходит, потому что константные свойства должны быть инициализированы перед init() возвращается, и если вы создаете представления в контроллере представления, у вас не будет возможности добавлять представления до loadView() называется. В этом случае объявите UIViews как неявно развернутые необязательные. Они будут установлены в nil от init() который соответствует требованию инициализации, тогда вы можете установить их на фактические представления позже, когда viewDidLoad() называется, например:

class MyViewController: UIViewController {
    var someSubview: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        someSubview = UIView()
        view.addSubview(someSubview)
        // now set constraints with SnapKit
    }
}
Другие вопросы по тегам