【发布时间】:2019-06-01 11:40:16
【问题描述】:
我有一个从xib 文件启动的自定义UIView 类。它具有名为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)
}
}
UIView 上的nib 属性的定义在另一个扩展中
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:EXC_BAD_ACCESS (code=EXC_I386_GPFLT)”而崩溃
调用堆栈顶部的方法是“ProgressView.title.modify”。
编辑 2- 我不确定我做了什么,但在重新启动 xcode 后我无法重现该问题。即使使用了计算属性,它也能按预期工作。
【问题讨论】:
-
如果您将
get更改为return titleLabel?.text ?? ""会发生什么 -
只要
return titleLabel?.text就足够了,因为title是String? -
“我认为这是因为” - 在调试器中运行您的代码,看看实际发生了什么,而不是做出假设。用您发现的内容更新您的问题。
-
仅供参考 - 当您使用存储属性时,getter 不会做任何事情。 getter 可能无法反映标签中的实际值。这与问题无关,但存储属性版本和计算值版本之间存在很大差异。
-
您应该在创建 ProgressView 的所有位置以及获取和设置 Computed 属性的所有行中添加断点。我会在 Xcode 中做,但我现在在我的 iPhone 上。关于究竟是什么导致了这个错误,这将是非常有用的。如果您在控制台/调试器中包含打印的错误名称,那也很棒。如果在我给电脑充电时这个问题还没有得到解答,我会试着弄清楚。
标签: ios swift getter-setter iboutlet