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

时间:2015-08-11 21:38:10

标签: swift swift2

在我正在处理的应用程序中,我尝试利用Swift中的新协议扩展功能。我的想法是我有很多类实现相同的协议。由于所有这些类都应该具有相同的计算属性,并且由于属性在不同的类中的行为应该相同,所以我认为仅添加一次该功能会很好。

我的代码结构如下:

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)
}

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

问题是扩展程序不支持存储的属性。但是,我在哪里/如何存储提交给计算属性的数据?

我可以想到两种不同的解决方案,但它们都不好......

  1. 我可以将扩展转换为实现SomeProtocol的类,然后使SomeClass成为它的子类。这将允许我将数据保存在存储的属性中。但是它还需要我实现协议在新类中所需的所有方法 - 这绝对没有意义,因为SomeClass的不同版本应该提供不同的功能..
  2. 我可以放弃整个扩展主题,并将所有属性移动到SomeProtocol。但这需要我在具有相同功能的SomeClass的所有不同版本中实现所有计算属性,并且我的扩展想法的重点是避免一遍又一遍地为相同的属性编写相同的实现。
  3. 是否有一些我忽略的完全简单的逻辑解决方案?

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

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

    ...或者我应该把它搞砸并使用我不那么漂亮的解决方案之一?

2 个答案:

答案 0 :(得分:0)

假设我正确地理解了这个问题,以解决协议扩展不支持存储属性这一事实,你可以扩展NSObject并使用目标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 :(得分:-1)

协议扩展?为什么?

有时候我们会这么想,我们忽略了一种直视着我们的实际解决方案。

<强> 1。你有一组计算属性吗?不,您需要存储的属性。

  

因为所有这些类都应具有相同的计算属性,并且   因为属性应该在不同的方面表现相同   类...

......但稍后

  

问题是扩展程序不支持存储的属性。   但是在哪里/如何存储提交给计算属性的数据   然后?

<强> 2。假设它是您想要的一组存储属性,您实际上自己提供了解决方案!做了一个现在有意义的改变。

  

我可以将扩展转换为实现的类   相反,SomeProtocol ,然后使SomeClass成为它的子类。那   允许我将数据保存在存储的属性中。

您可以随时扩展该类,然后 确认其子类到SomeProtocol以获取这些功能。这更清洁了。

另一方面,Swift的协议无法存储属性是设计上的。协议本身并不存在,在它们中添加存储的属性是没有意义的。