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

标签 ios swift getter-setter iboutlet

我有一个从 xib 文件启动的自定义 UIView 类。它具有名为 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)
    }
}

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 属性是计算而不是存储时的行为差异?

编辑 - 主线程崩溃并显示“Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)”

调用堆栈顶部的方法是“ProgressView.title.modify”。

编辑 2- 我不确定我做了什么,但在重新启动 xcode 后我无法重现该问题。即使使用计算属性,它也会按预期工作。

最佳答案

你的描述远非解释性的,但我猜测有一个 ProgressView nib,其中文件的所有者是一个 ProgressView,并且有一个从文件所有者到标签的 titleLabel 导出 Nib 内。 (我假设这是因为否则我无法解释您对 withOwner: self 的使用。)

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

我的代码在 View Controller 的 viewDidLoad 中,如果有区别的话。

(顺便说一句,我怀疑您对 ProgressView() 的使用。这会导致 View 大小为零。这似乎没有任何区别,但这是个坏主意。标签是零尺寸 View 的 subview 。如果零尺寸 View 剪裁了它的 subview ,标签将是不可见的。即使零尺寸 View 不剪裁其 subview ,如果标签是一个按钮,按钮不会工作。零大小的 View 是一个坏主意。你应该给你的 ProgressView 一个真正的框架。)

关于ios - 当计算实例变量而不是存储实例变量时,行为会有所不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56406393/

相关文章:

ios - 主观 iPhone/Core 数据设置民意调查

iphone - 如果仅在 Xcode 4.2 中使用 armv6 以支持新旧设备,有什么缺陷吗?

ios - 在将新界面推送到界面 Controller 上后,如何关闭由界面 Controller 组成的两个页面中不需要的页面?在 Watchkit 上

swift - 使用类中的函数初始化变量

ios - 使用带有添加的 WebAPI 参数的 NSDictionary

java - Android中如何全局访问SQl​​ite返回的数据?

objective-c - UIWebview 和 facebook 墙

ios - 预填充的 SQLite DB 文件不保存更新?

ruby-on-rails - 如何在使用虚拟属性时添加错误消息

r - 使用 R,如何将所有参数及其值传递给函数?