领域列表 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) 一种将 RLMObject
s 转换为 Object
s 的方法,要么 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()
}
}
}
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) 一种将 RLMObject
s 转换为 Object
s 的方法,要么 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()
}
}
}