我有一个自UIView
文件启动的自定义xib
类。它具有类型为title
的实例属性String?
。只要设置了title
属性,UITextField
的文本就会更改为title
属性的值。
如果title
属性是存储的属性,则程序将按预期运行。
如果title
属性是计算属性,那么程序会崩溃,并显示EXC_BAD_ACCESS
错误,我认为这是因为IBOutlet
尚未初始化。
任何人都可以解释为什么title
是一个存储属性,它可以工作,但是如果它是一个计算属性,它会失败吗?
以下是源代码-
NibView
是UIView
的子类,负责处理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)
}
}
nib
上UIView
属性的定义在另一个扩展名中
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
属性被计算而不是存储时,行为的差异在哪里?
答案 0 :(得分:2)
您的描述远非解释性的,但我想这里有一个ProgressView笔尖,其中文件的所有者是ProgressView,并且有一个titleLabel
出口,从文件所有者到笔尖内的标签。 (我之所以这样认为是因为否则我无法解释您对withOwner: self
的使用。)
基于这种假设,我无法重现任何问题。两种表达title
的方式对我来说都很好。我放置了print
语句,以确保正确的语句被调用,它是正确的;无论是didSet
还是计算属性的设置器,我们都可以正常加载,并且看到“正在加载”文本。
如果有区别,我的代码位于视图控制器的viewDidLoad
中。
(顺便说一句,我怀疑您对ProgressView()
的使用有所怀疑。这导致视图的尺寸为零。这似乎没有什么区别,但这是一个坏主意。标签是子视图如果大小为零的视图剪切了其子视图,则标签将是不可见的。即使大小为零的视图未剪切其子视图,如果标签是按钮,则该按钮也将不起作用。尺寸的视图不是一个好主意。您应该给ProgressView一个真实的框架。)