刷新可观察到

时间:2019-08-07 21:53:36

标签: swift rx-swift

我有一个可观察对象,它发出CNContacts列表,并且我想在Contacts数据库(.CNContactStoreDidChange)发生更改时重新加载该列表。

因此,可观察对象应该在订阅时发出一个值,并且每当其他可观察对象(通知)发出一个值时。听起来就像将它们与withLatestFrom组合在一起,但它不会发出任何东西。

let myContactKeys = [
    CNContactIdentifierKey as CNKeyDescriptor,
    CNContactFormatter.descriptorForRequiredKeys(for: .fullName)
]

func fetchContacts(by identifiers: [String],
                 contactKeys: [CNKeyDescriptor]) -> Observable<Event<[CNContact]>> {

    return Observable<[String]>.just(identifiers)
        .withLatestFrom(NotificationCenter.default.rx.notification(Notification.Name.CNContactStoreDidChange)) { ids, _ in ids}
        .flatMap { ids in
            Observable<[CNContact]>.create { observer in
                let predicate = CNContact.predicateForContacts(withIdentifiers: ids)
                do {
                    let contacts = try CNContactStore().unifiedContacts(matching: predicate, keysToFetch: contactKeys)
                    observer.onNext(contacts)
                } catch {
                    observer.onError(error)
                }

                return Disposables.create()
            }
            .materialize()
        }
        .observeOn(MainScheduler.instance)
        .share(replay: 1)
        .debug()
}

fetchContacts(by: ["123"], contactKeys: myContactKeys)
    .subscribe(
        onNext: { contacts in
            contacts.forEach { print($0.fullName) }
        },
        onError: { error in
            print(error.localizedDescription)
        })
    .dispose(by: disposeBag)

1 个答案:

答案 0 :(得分:1)

代码的问题是您从Observable<[String]>.just(identifiers)开始,它将发出您的标识符并立即完成。您不希望它完成,而是希望它在通知到来时继续发出值。

根据您的描述,听起来您想要类似以下内容。每当通知触发时,它就会发出,并从联系人开始。

let myContactKeys = [
    CNContactIdentifierKey as CNKeyDescriptor,
    CNContactFormatter.descriptorForRequiredKeys(for: .fullName)
]

func fetchContacts(by identifiers: [String], contactKeys: [CNKeyDescriptor]) -> Observable<Event<[CNContact]>> {

    func update() throws -> [CNContact] {
        let predicate = CNContact.predicateForContacts(withIdentifiers: identifiers)
        return try CNContactStore().unifiedContacts(matching: predicate, keysToFetch: contactKeys)
    }
    return Observable.deferred {
        NotificationCenter.default.rx.notification(Notification.Name.CNContactStoreDidChange)
            .map { _ in }
            .map(update)
            .materialize()
        }
        .startWith({ () -> Event<[CNContact]> in
            do {
                return Event.next(try update())
            }
            catch {
                return Event.error(error)
            }
        }())
        .share(replay: 1)
        .debug()
}