计算实例变量而不是存储实例变量时,行为上会有所不同

时间:2019-06-01 11:40:16

标签: ios swift getter-setter iboutlet

我有一个自UIView文件启动的自定义xib类。它具有类型为title的实例属性String?。只要设置了title属性,UITextField的文本就会更改为title属性的值。

如果title属性是存储的属性,则程序将按预期运行。

如果title属性是计算属性,那么程序会崩溃,并显示EXC_BAD_ACCESS错误,我认为这是因为IBOutlet尚未初始化。

任何人都可以解释为什么title是一个存储属性,它可以工作,但是如果它是一个计算属性,它会失败吗?

以下是源代码- NibViewUIView的子类,负责处理xib文件

class NibView: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        loadNib()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        loadNib()
    }
}

loadNib方法的实现在扩展程序内部

extension UIView {
    func loadNib() {
        guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else { return }

        view.frame = bounds
        addSubview(view)
    }
}

nibUIView属性的定义在另一个扩展名中

extension UIView {
    static var nib: UINib {
        return UINib(nibName: String(describing: self), bundle: nil)
    }

    var nib: UINib {
        return type(of: self).nib
    }
}

以下类是具有title属性的类。

class ProgressView: NibView {
    var title: String? {
        didSet {
            titleLabel.text = title
        }
    }

    @IBOutlet private weak var titleLabel: UILabel!
}

以上类的用法如下-

let view = ProgressView()
addSubview(view)
view.title = "Loading"

运行上面的代码按预期工作。 但是,如果将ProgressView的实现更改为使用如下所示的计算属性,则它将失败

class ProgressView: NibView {
    var title: String? {
        get {
            return titleLabel.text
        }
        set {
            titleLabel.text = newValue
        }
    }

    @IBOutlet private weak var titleLabel: UILabel!
}

有人能指出为什么title属性被计算而不是存储时,行为的差异在哪里?

1 个答案:

答案 0 :(得分:2)

您的描述远非解释性的,但我想这里有一个ProgressView笔尖,其中文件的所有者是ProgressView,并且有一个titleLabel出口,从文件所有者到笔尖内的标签。 (我之所以这样认为是因为否则我无法解释您对withOwner: self的使用。)

基于这种假设,我无法重现任何问题。两种表达title的方式对我来说都很好。我放置了print语句,以确保正确的语句被调用,它是正确的;无论是didSet还是计算属性的设置器,我们都可以正常加载,并且看到“正在加载”文本。

如果有区别,我的代码位于视图控制器的viewDidLoad中。

(顺便说一句,我怀疑您对ProgressView()的使用有所怀疑。这导致视图的尺寸为零。这似乎没有什么区别,但这是一个坏主意。标签是子视图如果大小为零的视图剪切了其子视图,则标签将是不可见的。即使大小为零的视图未剪切其子视图,如果标签是按钮,则该按钮也将不起作用。尺寸的视图不是一个好主意。您应该给ProgressView一个真实的框架。)