【问题标题】:Swift: property observers for computed propertiesSwift:计算属性的属性观察者
【发布时间】:2016-04-22 04:32:15
【问题描述】:

据我所知,Swift 允许我们为存储和计算属性设置属性观察器。但是如果计算出的属性值依赖于一些后备存储,当这些后备存储值发生更改时,不会触发属性观察器:

public class BaseClass {
    private var privateVar1: Int = 0
    private var privateVar2: Int = 0
    public var property: Int {
        get {
            return privateVar1 * privateVar2
        }
        set {
            print("some setter without effect")
        }
    }
    private func changeSomeValues() {
        privateVar1 = 1
        privateVar2 = 2
    } 
}

public class SubClass : BaseClass {
    override var property: Int {
        didSet {
            print("didSet \(property)")
        }
    }
}

调用 changeSomeValues 时不调用 SubClass 的didSet。

让我们考虑一个案例:我们在第三方框架中有这样的 BaseClass。我们在我们的应用程序中定义子类。问题是:我们如何在不了解属性性质的情况下依赖子类观察者:它是存储的(我们可以依赖观察者)还是计算的(然后我们不能期望每次都在我们期望的时候触发观察者)?可能吗?如果不是,是否违反封装?

【问题讨论】:

  • 您的代码无效且无法编译。 property 是只读的。如果property 是一个读写计算属性,那么didSet 将在子类上触发,正如您所期望的那样。

标签: ios swift computed-properties


【解决方案1】:

这种行为是完全正常的。编译器无法知道哪个后备存储真正对应于哪个计算属性。在这种情况下,您的后备存储由私有变量组成,这些变量在类本身之外无法访问。因此,唯一可能发生“幕后”变化的地方是基类。使用其计算属性(将触发观察者)或后备存储(不会触发)是该类的特权。

在您的示例中,假设您从不希望允许“不可见”更改,则 changeSomeValues() 函数违反了自己的规则,并且不尊重它向其子类和调用者承诺的合同。

【讨论】:

  • 例如,我的基类是UView,一个属性是frame。没有人知道它是计算属性还是存储属性,因为它是一个实现细节。问题是:每次我期望的每一次frame 更改我都可以依靠触发 didSet 吗?如果是,如何保证和实施?如果不是,是否会使财产观察者的整个概念变得无用?
  • Apple 没有保证观察 frame 属性。如果您想将其添加到合同中,您可能会陷入困境。我没有详细阅读文档,但我相信框架只是一个方便的概念来访问边界和中心,这是真正推动 UIView 设计的核心概念。无论如何,Apple 的文档建议对我不喜欢的所有视图属性使用 KVO。 developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
  • 您还必须记住,Swift 出现的时间并不长。多年来,Objective-C 一直是山丘之王,iOS/OSX 框架的设计受到了旧语言结构和渐进式发展的特性和限制的严重污染。如果 iOS 是使用 Swift 创建的,那么 API 和类设计将利用更多 Swift 的特性。好消息是,苹果正在逐步做到这一点。例如从 NSError 返回值转移到 do/catch 块。
猜你喜欢
  • 2020-03-03
  • 2017-04-25
  • 1970-01-01
  • 1970-01-01
  • 2015-04-28
  • 2020-11-20
  • 1970-01-01
  • 2015-03-30
  • 1970-01-01
相关资源
最近更新 更多