领域列表 KVO 观察

Realm List KVO observation

Realm Swift 文档指出,您在模型 class 上使用的大多数属性都可以使用 KVO 观察到。使用 ReactiveCocoa,对于模型 class 上的每个 属性,我创建了一个可比较的 rac_ 前缀 属性 发送值更改,然后我可以使用它绑定到视图MVVM 风格的架构。

示例模型 class 可能如下所示:

 class Post: Object {
     dynamic var text = ""
     private(set) lazy var rac_text: AnyProperty<String> = { [unowned self] in
         return AnyProperty(initialValue: self.name, signal: self.rac_valuesForKeyPath("text", observer: self).toSignal().takeUntil(self.willDeallocSignal())
     }()
 }

这非常方便,因为 1) 它从外部是不可改变的(AnyProperty vs MutableProperty 和 2)只要模型使用 .takeUntil(self.willDeallocSignal()) 就可以。 (我也想问一下,[unowned self]这里有必要吗?我不确定self是否被捕获,一直很糟糕)。

问题来自 List 属性。列表不能标记为动态的,这是有道理的,它们的类型不能在 objective-c 中表示。键值观察效果很好,但有一个主要警告。

取相同的class与关系列表属性:

class Post: Object {
    let users: List<User> = List<User>()
}

相应的反应性观察 属性 应该类似于:

private(set) lazy var rac_users: AnyProperty<List<User>> = {
    return AnyProperty(initialValue: self.users, signal: self.rac_valuesForKeyPath("users", observer: self).toSignal().takeUntil(self.willDeallocSignal()))
}()

但是根据观察,信号不会发射 List 个物体,它会发射 RLMArray 个物体。我不得不 jerryrig 一个看起来像这样的信号生成器:

private(set) lazy var rac_posts: AnyProperty<List<Post>> = { [unowned self] in
    return AnyProperty<List<Post>>(initialValue: self.posts, producer: self.rac_valuesForKeyPath("posts", observer: self)
        .toSignalProducer()
        .assumeNoErrors()
        .map { [=13=] as! RLMArray }
        .map { array in
            var list = List<Post>()
            for i in 0..<array.count {
                if let element =  array[i] as? Post {
                    list.append(element)
                }
            }
            return list
    })
}()

当然,if let 语句总是失败,因为 RLMObject 无法转换为 Post。所以我要么需要 a) 一种将 RLMObjects 转换为 Objects 的方法,要么 b) 一种在发出列表的列表 属性 上进行 kvo 的方法。我用传统的 KVO 测试了它,得到了相同的结果。

您可以使用 addNotificationBlock.

观察类型 List 与领域 Swift 的属性

此方法需要一个闭包,在每次 更改时调用该闭包。至少只要您不阻止 运行 循环,通知就可能合并。初始值也会通过此机制报告,因此您可能会通过它获得额外的信号,这可能是您意想不到的。

您应该可以使用 Reactive Cocoa 将其连接起来,如下所示:

private(set) lazy var rac_posts: AnyProperty<List<Post>> = { [unowned self] in
    return AnyProperty<List<Post>>(initialValue: self.posts, signal: Signal<List<Post>>() { [unowned self] observer in
        let notificationToken = self.posts.addNotificationBlock { list in
            observer.sendNext(list)
        }

        return ActionDisposable() {
            notificationToken.stop()
        }
    }
}()

合并 #3359 后,您还会收到细粒度的通知,通知您列表中的详细更改。

func observeAppVarProperties(properties: [String]) -> Observable<AppVarsObject> {
        return Observable.create { observer in
            guard let globals = try! Realm().objects(AppVarsObject.self).first else {
                observer.onError(NSError(domain: "", code: 0, userInfo: nil))
                return Disposables.create()
            }
            observer.onNext(globals)
            let notificationToken = globals.observe { (changed) in
                switch changed {
                case .change(let propertyChanges):
                    if propertyChanges.filter({ properties.contains([=10=].name) }).count > 0 {
                        observer.onNext(globals)
                    }
                case .deleted:
                    observer.onNext(globals)
                case .error(let error):
                    observer.onError(error)
                }
            }
            return Disposables.create {
                notificationToken.invalidate()
            }
        }
    }