连接 Realm 和 SwiftBond 的最佳方式是什么

What is the best way to connect Realm and SwiftBond

我爱Realm and I love Bond。它们都使应用程序创建成为一种乐趣。所以我想知道连接 Realm 和 Bond 的最佳方式是什么?
在 Realm 中,我们可以存储基本类型,例如 IntString,例如但在 Bond 中,我们使用 Dynamics 和 Bonds。我发现连接 Realm 和 Bond 的唯一方法如下:

class TestObject: RLMObject {

   dynamic var rlmTitle: String = ""
   dynamic var rlmSubtitle: String = ""

   var title: Dynamic<String>
   var subtitle: Dynamic<String>

   private let titleBond: Bond<String>!
   private let subtitleBond: Bond<String>!

   init(title: String, subtitle: String) {
      self.title = Dynamic<String>(title)
      self.subtitle = Dynamic<String>(subtitle)

      super.init()

      self.titleBond = Bond<String>() { [unowned self] title in self.rlmTitle = title }
      self.subtitleBond = Bond<String>() { [unowned self] subtitle in self.rlmSubtitle = subtitle }

      self.title ->> titleBond
      self.subtitle ->> subtitleBond
   }
}

但它确实缺乏简洁和优雅,并且会产生大量的锅炉代码。有什么办法可以做得更好吗?

如果您使用 默认 属性 值:

  class TestObject: RLMObject {

     dynamic var rlmTitle = ""
     dynamic var rlmSubtitle = ""

     var title: Dynamic<String>
     var subtitle: Dynamic<String>

     private let titleBond = Bond<String>() { [unowned self] title in self.rlmTitle = title }
     private let subtitleBond = Bond<String>() { [unowned self] subtitle in self.rlmSubtitle = subtitle }

     init(title: String, subtitle: String) {
        self.title = Dynamic<String>(title)
        self.subtitle = Dynamic<String>(subtitle)
        self.title ->> titleBond
        self.subtitle ->> subtitleBond

        super.init()
     }
  }

如果 Bond 的 ->> 运算符返回了 左值所以你可以做 self.title = Dynamic<String>(title) ->> titleBond.

但最终,在 Swift 具有对 KVO 或等效观察机制的本地语言支持之前,遗憾的是您将不得不编写一些样板文件。

我考虑了三天,想出了近乎完美的解决方案,没有使用任何样板代码。首先,我为领域模型的包装器创建了一个超级 class:

class BondRealmBaseClass {

   private var realmModel: RLMObject!
   private let realm = RLMRealm.defaultRealm()
   private var bonds = NSMutableArray()

   init(){
      realmModel = createRealmModel()
      realm.beginWriteTransaction()
      realm.addObject(realmModel)
      realm.commitWriteTransaction()
      createBonds()
   }

   init(realmModel: RLMObject){
      self.realmModel = realmModel
      createBonds()
   }

   func createBondFrom<T>(from: Dynamic<T>, toModelKeyPath keyPath: String){
      from.value = realmModel.valueForKeyPath(keyPath) as T
      let bond = Bond<T>() { [unowned self] value in
         self.realm.beginWriteTransaction()
         self.realmModel.setValue(value as NSObject, forKey: keyPath)
         self.realm.commitWriteTransaction()
      }
      from ->| bond
      bonds.addObject(bond)
   }

   //MARK: - Should be overriden by super classes
   func createBonds(){ fatalError("should be implemented in supreclass") }
   func createRealmModel() -> RLMObject{ fatalError("should be implemented in supreclass") }
}

之后我为每个领域模型创建两个 classes,第一个是实际的领域模型,它存储所有属性:

class RealmTodoModel: RLMObject { 
   dynamic var title = ""
   dynamic var date = NSDate()
}

第二个是领域模型的包装器:

class TodoModel : BondRealmBaseClass{
   let title = Dynamic("")
   let date = Dynamic(NSDate())

   override func createBonds(){
      createBondFrom(title, toModelKeyPath: "title")
      createBondFrom(date, toModelKeyPath: "date")
   }

   override func createRealmModel() -> RLMObject { return RealmTodoModel() }
}

而这两个 classes 实际上是 link RealmBond 所需要的:创建新的 TodoModel 实际上会添加到 Realm new RealmTodoModelTodoModeltitledate 所做的所有更改将自动保存到相应的 Realm 模型!

编辑

我添加了一些功能并将其作为框架发布在 GitHub 上。这里是 link.

借助支持 KVO 和 Bond 4 的 Realm,您可以扩展 Realm 对象以提供 Observable 变体。它有一些样板,但很干净,没有黑客攻击。

class Dog: Object {
  dynamic var name = ""
  dynamic var birthdate = NSDate(timeIntervalSince1970: 1)
}

extension Dog {

  class ObservableDog {
    let name: Observable<String>
    let birthdate: Observable<NSDate>

    init(dog: Dog) {
      name = Observable(object: dog, keyPath: "name")
      birthdate = Observable(object: dog, keyPath: "birthdate")
    }
  }

  func observableVariant() -> Dog.ObservableDog {
    return ObservableDog(dog: self)
  }
}

你能做到的:

let myDog = Dog().observableVariant()

myDog.name.observe { newName in
  print(newName)
}

myDog.name.bindTo(nameLabel.bnd_text)

realm.write {
  myDog.name.value = "Jim"
}