我有一个可观察对象,它发出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)
答案 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()
}