领域列表KVO观察

时间:2016-04-15 04:56:54

标签: ios swift mvvm realm reactive-cocoa

Realm Swift文档指出,您可以使用KVO观察模型类上使用的大多数属性。使用ReactiveCocoa,对于模型类中的每个属性,我创建了一个类似的rac_前缀属性,它发送值更改,然后我可以使用它来绑定到MVVM样式体系结构中的视图。

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

 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 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 { $0 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转换为Object s或b)在列表属性上发送kvo的方式。我使用传统的KVO测试它并得到了相同的结果。

2 个答案:

答案 0 :(得分:1)

您可以使用addNotificationBlock在Realm Swift中观察List类型的属性。

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

你应该可以使用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后,您还会收到细粒度的通知,通知您列表中的详细更改。

答案 1 :(得分:0)

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($0.name) }).count > 0 {
                        observer.onNext(globals)
                    }
                case .deleted:
                    observer.onNext(globals)
                case .error(let error):
                    observer.onError(error)
                }
            }
            return Disposables.create {
                notificationToken.invalidate()
            }
        }
    }