Search code examples
swiftfirebasefirebase-realtime-databaserx-swift

Handling Null ref from firebase


I have an application where I am using Firebase and RxSwift. I am getting snapshot from a ref and the issue I have now is the ref could be null i.e it does not exist. how do I still make my code run to by pass the null reason

if Null, I should call onCompleted.

func refreshActiveTrip() -> Observable<Trip> {

        guard let trip = getCurrentTrip()  else {
            return Observable.error(RxError.noElements)
        }

        tripRef = Database.database().reference(forTransportChampionId: (getChampion()?.id)!, tripId: trip.id!)
        return Observable<Trip>.create({ (observer) -> Disposable in

            let disposable = Disposables.create {
                self.tripRef?.removeAllObservers()
            }

            self.tripRef?.observeSingleEvent(of: .value, with: { (snapshot) in
                if snapshot.exists(){

                    if let data = snapshot.value as? [String: AnyObject] {

                        let trip = Trip(dictionary: data as NSDictionary)
                        print("SPLASH TRIP CURRENT \(data)")

                        self.saveCurrentTrip(trip)
                        observer.onNext(trip)
                        observer.onCompleted()

                    }
                    print("It exists!!")
                }else{
                    let trip = Trip()
                    self.saveCurrentTrip(trip)
                    print("Nope, doesn't exist!")
                }
            })

            return disposable
        })

    }

the tripRef could be null


Solution

  • Since you are already creating an Observable with Observable.create(), you can simply call observer.onCompleted() in your else clause.

    That said, it seems to me that you should be emitting the Trip() object that you created instead and then saving it outside this function.


    More information:

    For what you are doing, would expect something more like this:

    func refreshActiveTrip(_ trip: Trip?, championId: String) -> Observable<Trip> {
        guard let trip = trip else { return Observable.error(RxError.noElements) }
        return Observable.create { observer in
            let tripRef = Database.database().reference(forTransportChampionId: championId, tripId: trip.id!)
            tripRef.observeSingleEvent(of: .value, with: { snapshot in
                var trip = Trip()
                if snapshot.exists(), let data = snapshot.value as? [String: AnyObject] {
                    trip = Trip(dictionary: data as NSDictionary)
                }
                observer.onNext(trip)
                observer.onCompleted()
            })
            return Disposables.create { tripRef.removeAllObservers() }
        }
    }
    

    Note that the above is a free function; it is not inside any class.

    To fully realize the code you have, it would be used like this:

    refreshActiveTrip(getCurrentTrip(), championId: getChampion()!.id!)
        .do(onNext: { [weak self] trip in self?.saveCurrentTrip(trip) })
        .filter { $0.id != nil }
    

    Presumably, the above would be in a flatMap that catches errors...

    Lastly, you should consider using RxFirebase