Firebase FirestoreのデータをRxSwiftで取得するためのメモ
メモなので今後も追記予定
func getData() -> Observable<[Model]?> {
guard let uid = Auth.auth().currentUser?.uid else { return Observable.just(nil) }
return Observable.create { (observer: AnyObserver<Model?>) -> Disposable in
Firestore.firestore().document("path to data/\(uid)").getDocument { (document, error) in
if let error = error {
observer.onError(error)
return
}
guard let document = document, document.exists else {
observer.onError( /* データなしエラー */ )
return
}
// DocumentSnapshottから変換して返す
let model = try? Model(from: document)
observer.on(.next(model))
observer.onCompleted()
}
return Disposables.create()
}
}
RxFirebaseを使う場合
func getData() -> Observable<[Model]?> {
guard let uid = Auth.auth().currentUser?.uid else { return Observable.just(nil) }
return database.collection("path to datas").document(uid).rx.getDocument().map(Model.init)
}
オプショナルをなくす場合
func getData() -> Observable<[Model]> {
guard let uid = Auth.auth().currentUser?.uid else { return Observable.error( /* 定義していた何かのエラー */ ) }
return database.collection("path to datas").document(uid).rx.getDocument().map(Model.init)
}
利用例
Category というモデルがある場合
Serviceクラスを作成
class CategoryService {
private static let database = Firestore.firestore()
static func getCategories() -> Observable<[Category]> {
return database.collection("/category")
.whereField("status", isEqualTo: 1)
.rx.getDocuments() // QuerySnapshot
.map { $0.documents } // [QueryDocumentSnapshot]
.map { $0.compactMap{ doc in return try? Category.init(from: doc) } } // [Category]
}
}
ViewModel はこんな風に
class ViewModel {
let categories: Driver<[Category]>
let error: Driver<Error>
init () {
(self.categories, self.error) = Driver.split(result: CategoryService.getCategories().resultDriver())
}
}
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
private var viewModel: ViewModel!
let caategories = BehaviorRelay<[Category]?>(value: [])
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// データ取得
self.viewModel = ViewModel()
// カテゴリ情報を bind
self.viewModel.categories.asObservable()
.bind(to: self.caategories)
.disposed(by: rx.disposeBag)
// カテゴリ情報を bind した後に一覧を更新
self.caategories.asDriver().drive(onNext: { [unowned self] _ in
self.tableView.reloadData()
}).disposed(by: rx.disposeBag)
}
}