如何在协议扩展中存储提交给计算属性的数据?

How do I store data submitted to computed properties in a protocol extension?

在我目前正在开发的应用程序中,我尝试利用 Swift 中的新协议扩展功能。这个想法是我有很多 classes 实现相同的协议。由于所有这些 classes 应该具有相同的计算属性,并且由于这些属性在不同的 classes 中应该表现相同,所以我认为只添加一次功能会很好。

我的代码结构如下例

protocol SomeProtocol { ... }

// There could potentially be unlimited different versions of "SomeClass" that implements "SomeProtocol"
class SomeClass : SomeProtocol { ... }

extension SomeProtocol {
    var computedProperty1: Type? {
        get { getData(SOME_ENUM) }
        set { validateAndSave(newValue, atKey: SOME_ENUM) }
    }
    var computedProperty2: Type? {
        get { getData(SOME_OTHER_ENUM) }
        set { validateAndSave(newValue, atKey: SOME_OTEHR_ENUM) }
    }
    ...

    func getData(atKey: ENUM_TYPE) -> Type? {
        [NEED SOME WAY TO GET THE SAVED DATA AND RETURN IT]
    }
    func validateAndSave(value: Type?, atKey: ENUM_TYPE) {
        [NEED SOME WAY TO SAVE DATA FOR LATER RETURNING]
    }
}

// The properties needs to be visible to the client code like this:
class ClientCode {
    let someClassObject: SomeProtocol = SomeClass()
    someClassObject.computedProperty1 = Type()
    print(someClassObject.computedProperty1)
}

(上面的代码显示了将数据存储在不同字典中的迹象,这是我的第一个想法)

问题是扩展不支持存储属性。但是 where/how 我是否存储提交给计算属性的数据?

我可以想到 2 种不同的解决方案,但 none 个都不错..

  1. 我可以将扩展转换为实现 SomeProtocol 的 class,然后使 SomeClass 成为它的子 class。这将允许我将数据保存在存储的属性中。但这也需要我在新 class 中实现协议所需的所有方法——这完全没有意义,因为 SomeClass 的不同版本应该提供不同的功能..
  2. 我可以放弃整个扩展想法,将所有属性移至 SomeProtocol。但这将需要我在所有不同版本的 SomeClass 中实现所有计算属性,并具有相同的功能,而我的扩展想法的重点是避免一遍又一遍地为相同的属性编写相同的实现。 .

是否有一些我忽略了的完全简单的逻辑解决方案?

...或者在我不知道的协议扩展中保存数据的好方法?

...或其他获得所需功能的方法?

...或者我应该接受它并使用我不太漂亮的解决方案之一?

假设我正确理解问题以解决协议扩展不支持存储属性这一事实,您可以扩展 NSObject 并使用 objective C 运行时来存储您的属性。

import ObjectiveC

private var AssociationKey: UInt8 = 0

class YourStoredObject {
  // Whatever object your are persisting
}

extension NSObject {
  var yourStoredObject: (YourStoredObject)! {
    get {
      return objc_getAssociatedObject(self, &AssociationKey) as? YourStoredObject
    }
    set(newValue) {
      objc_setAssociatedObject(self, &AssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
    }
  }
}

protocol YourProtocol {
  var yourStoredObject: YourStoredObject! { get set }
}

extension YourProtocol {

  func customYourStoredObjectGetter() -> YourStoredObject {
    return yourStoredObject
  }

}

extension UILabel : YourProtocol {

  func myExtendedFunc() {
    // Get (and print) your object directly
    print(yourStoredObject)
    // Get your object through a protocol custom getter
    print(customYourStoredObjectGetter())

    // Set your object
    yourStoredObject = YourStoredObject()
  }
}

我并不是说这是最好的解决方案,但这是我能想到的唯一解决方案。我也在寻找更好的 Swift 替代品,但仍然没有找到。

协议扩展?为什么?

有时我们太执着于一个想法,以至于忽略了眼前的实际解决方案。

1.你有一组计算属性吗?不,您需要存储属性。

Since all these classes should have the same computed properties, and since the properties should behave identically in de different classes...

...但后来

The problem is that an extension does not support stored properties. But where/how do I store the data submitted to the computed properties then?

2。假设它是一组你想要的存储属性,你几乎自己提供了解决方案!进行了一项现在有意义的更改。

I could transform the extension into a class that implements SomeProtocol instead, and then make SomeClass a subclass of it. That would allow me to save the data in stored properties.

您可以随时扩展 class 并 然后 确认其子 class 为 SomeProtocol 以获得功能。这个更干净。

附带说明一下,Swift 的协议无法存储属性是设计使然。协议本身并不存在,在其中添加存储属性没有意义。