Swift数据模型中的动态属性(getter/setter)

Swift数据模型中的动态属性(getter/setter),swift,swift2,Swift,Swift2,我正在尝试使用Swift(这是我的新手)为我的数据模型创建一个干净的界面。这些模型得到了Firebase的支持(尽管这最终与实际问题无关)。我想要避免的是一遍又一遍地编写大量setter/accessor锅炉板代码 例如: class MyData { let connection: Firebase! private var _name: String? // internal storage, like an iVar in ObjC init(connection: Fir

我正在尝试使用
Swift
(这是我的新手)为我的数据模型创建一个干净的界面。这些模型得到了Firebase的支持(尽管这最终与实际问题无关)。我想要避免的是一遍又一遍地编写大量setter/accessor锅炉板代码

例如:

class MyData {
  let connection: Firebase!

  private var _name: String? // internal storage, like an iVar in ObjC

  init(connection: Firebase!) {
    self.connection = connection
    self.connection.observeEventType(.Value, withBlock: { snapshot in
      _name = snapshot["name"]
    }
  }

  var name: {
    get {
      return _name
    }
    set(name) {
      // When the client sets the name, write it to Firebase
      _name = name
      self.connection.childByAppendingPath("name").setValue(name)
    }
  }
}
我肯定我在这方面犯了很多错误。其思想是在实例化实例时首先从服务器加载数据。随后,我们可以调用
my\u data\u instance.name
来获取该名称,或者
my\u data\u instance.name=“foo”
并将该名称自动写入服务器

对于单个属性(其中将有许多属性),这需要大约10行代码。坚果一定有更好的办法



编辑:为了清楚起见,我想避免编写尽可能多的锅炉铭牌代码。考虑一个库,例如“代码> Test< <代码>,这里只定义一个<代码>属性就足以满足您的需要。在我看来,任何超过一行代码的内容都过于冗长。
我有一个名为“name”的属性,通过Firebase处理它。

Swift提供了名为property observer的功能

在更改值之前,还有第二个观察者
将设置
,称为

注(来自文件):

为存储的属性指定默认值或设置其 初始值在初始值设定项中,设置该属性的值 直接,无需致电任何财产观察员

您可以使用监视属性中的更改。更多信息请访问

<代码>导入基础 私有变量KVOContext=0 //您的类必须从NSObject继承 类MyData:NSObject{ 私有出租房地产观察=[“名称”,“位置”] 动态变量名:String 动态变量位置:字符串 init(名称:String,位置:String){ self.name=名称 self.location=位置 super.init() //添加要观察的属性 对于self.propertiesToObserve中的属性{ addObserver(self,forKeyPath:属性,选项:[.New,.Old],上下文:&KVOContext) } } //只要观察到的属性发生更改,就会调用此方法 重写func observeValueForKeyPath(键路径:String?,对象对象的类型:AnyObject?,更改:[String:AnyObject]?,上下文:UnsafeMutablePointer){ 如果let property=keyPath, newValue=更改![NSKeyValueChangeNewKey], oldValue=更改![NSKeyValueChangeOldKey]{ 打印(“\(属性)从\(旧值)更改为\(新值)”) //如果oldValue!=newValue,则写回Firebase } } //移除自我作为自我的观察者 脱硝{ 对于self.propertiesToObserve中的属性{ self.removeObserver(self,forKeyPath:property) } } } let data=MyData(名称:“John”,位置:“Chicago”) data.name=“David”//print:姓名从John改为David data.location=“纽约”//print:地点从芝加哥改为纽约
当然可以,但每个属性的代码量仍然很大。我们只减少了几行。很抱歉,这是Swift中最短的解决方案。在我的示例中,我使用了iVar,因为我不希望setter回写到firebase。也就是说,当
load
完成时,您的代码是否会调用
didSet
,从而为每次读取创建写操作?
didSet
不是在
init
方法中调用的,我用文档中的一段引用更新了答案,我可能需要在任何时间点从服务器加载数据,不仅仅是在
init
中,为了同步,您可以使用Objective-C运行时的元编程功能来动态批量添加属性。
var name: String {
   didSet {
     self.connection.childByAppendingPath("name").setValue(name)
   }
}
import Foundation

private var KVOContext = 0

// Your class must inherit from NSObject
class MyData : NSObject {
    private let propertiesToObserve = ["name", "location"]

    dynamic var name: String
    dynamic var location: String

    init(name: String, location: String) {
        self.name = name
        self.location = location
        super.init()

        // Add the properties that you want to observe
        for property in self.propertiesToObserve {
            self.addObserver(self, forKeyPath: property, options: [.New, .Old], context: &KVOContext)
        }
    }

    // This method is called whenever an observed property is changed
    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        if let property = keyPath,
            newValue = change![NSKeyValueChangeNewKey],
            oldValue = change![NSKeyValueChangeOldKey] {
                print("\(property) changed from \(oldValue) to \(newValue)")
                // If oldValue != newValue, write back to Firebase
        }
    }

    // Remove self as observer of self
    deinit {
        for property in self.propertiesToObserve {
            self.removeObserver(self, forKeyPath: property)
        }
    }
}

let data = MyData(name: "John", location: "Chicago")
data.name = "David"         // print: name changed from John to David
data.location = "New York"  // print: location changed from Chicago to New York