上記の公式ドキュメントを参考にクエリによる条件一致に該当するスナップショットのリスナーをObservableにした場合、以下のような実装になります。
extension Reactive where Base: Firestore { func observe<T: EntityProtcol>(collectionKey: String, fieldKey: String, fieldValue: Any) -> Observable<[T]> { return Observable.create({ (observer: AnyObserver<[T]>) -> Disposable in self.base .collection(collectionKey) .whereField(fieldKey, isEqualTo: fieldValue) .addSnapshotListener { querySnapshot, error in if let err = error { observer.on(.error(err)) return } if let snapshot = querySnapshot { let entities: [T] = snapshot.documents.compactMap {T.makeResult(document: $0.data())} observer.on(.next(entities)) } } return Disposables.create() }) } }
上記のExtensionをRepositoryなどで使用、つまりリスナーをアタッチします。その為上記ではSubscriverが都度受信するのはObservableなEntitiesになります。
func observe(userId: String) -> Observable<[RoomEntity]> { return Firestore.firestore().rx.observe(collectionKey: "test_rooms", fieldKey: "user_id", fieldValue: userId) }
ただこの場合、リスナーをアタッチした際 addSnapshotListener
の戻り値ListenerRegistration
が受け取れないためデタッチすることができません。
なのでFirestore+RxのExtension側のメソッドobserve()
をcallback関数としRepositoryなどの使用もとでクロージャを受け取ります。
func observeCollection<T: EntityProtcol>( collectionKey: String, fieldKey: String, fieldValue: Any, callback: @escaping (ListenerRegistration) -> Void) -> Observable<[T]> { return Observable.create({ (observer: AnyObserver<[T]>) -> Disposable in let listener = self.base .collection(collectionKey) .whereField(fieldKey, isEqualTo: fieldValue) .addSnapshotListener { querySnapshot, error in if let err = error { observer.on(.error(err)) return } if let snapshot = querySnapshot { let entities: [T] = snapshot.documents.compactMap {T.deserialize(document: $0.data())} observer.on(.next(entities)) } } callback(listener) return Disposables.create() }) }
func observe(userId: String) -> Observable<[RoomEntity]> { return Firestore .firestore() .rx.observeContainsCollection( collectionKey: "test_rooms", fieldKey: "user_id", fieldValue: userId) { [weak self] listener in self?.listener = listener } }
そしてメンバ変数のlistenerに対してremove()する関数を定義して適切なタイミングでデタッチを行えます。
func detach() { self.listener?.remove() }
- 作者:荻原 剛志
- 発売日: 2019/11/15
- メディア: 単行本