使用Combine进行响应的转换回调方法

问题描述 投票:0回答:1

这是我在做什么:

->使用FirebaseAuthentification登录/注册到Firebase

->侦听AuthStateDidChangeListenerHandle

->我在Firestore中存储了额外的用户信息,因此我检查该用户是否存在于Firestore中

->如果该用户不存在,我将创建一个空用户

->如果一切成功,我将通过回调返回Future Publisher(我也想更改它)

这是checkLoginState函数:

func checkLoginState(completion: @escaping (AnyPublisher<AccountDetails,Error>) -> Void) {
    self.handler = Auth.auth().addStateDidChangeListener { [weak self] auth, user in
        guard let safeSelf = self else { return }
        completion(Future<AccountDetails,Error> { promise in
            if let user = user {
                print(user)
                print(auth)

                safeSelf.checkIfUserIsInDatabase(user: user.uid) { result in
                    switch result {
                    case .success(let isAvailable):
                        if isAvailable {
                             promise(.success(AccountDetails(userUID: user.uid,name: user.displayName, loggedIn: true, premiumUser: false)))
                        } else {
                            safeSelf.createEmptyUser(user: user.uid,email: user.email) { result in
                                switch result {
                                case .success(_):
                                    promise(.success(AccountDetails(userUID: user.uid,name: user.displayName, loggedIn: true, premiumUser: false)))
                                case .failure(let error):
                                    print(error)
                                }
                            }
                        }
                    case .failure(let error):
                        print(error)
                    }
                }
            } else {
                promise(.success(AccountDetails(userUID: nil, loggedIn: false, premiumUser: false)))
            }
            }.eraseToAnyPublisher()
        )
    }
}

这些是我当前的功能:

private func checkIfUserIsInDatabase(user id: String, completion: @escaping (Result<Bool,Error>) -> Void)

private func createEmptyUser(user id: String, email:String?, completion: @escaping (Result<Bool,Error>) -> Void)

这就是我想使用的:

private func checkIfUserIsInDatabase(user id: String) -> AnyPublisher<Bool,Error>

private func createEmptyUser(user id: String) -> AnyPublisher<Bool,Error>

func checkLoginState() -> AnyPublisher<AccountDetails,Error>

我有类似的东西,但是它不起作用,看起来也很混乱:

func checkLoginState(completion: @escaping (AnyPublisher<AccountDetails,Error>) -> Void) {
    self.handler = Auth.auth().addStateDidChangeListener { [weak self] auth, user in
        guard let safeSelf = self else { return }
        completion(Future<AccountDetails,Error> { promise in
            if let user = user {
                print(user)
                print(auth)

                safeSelf.checkIfUserIsInDatabase(user: user.uid)
                    .sinkToResult { value in
                        switch value {
                        case .success(let isUserInDatabase):
                            if isUserInDatabase {
                                promise(.success(AccountDetails(userUID: user.uid,name: user.displayName, loggedIn: true, premiumUser: false)))
                            } else {
                                safeSelf.createEmptyUser(user: user.uid)
                                    .sinkToResult { value in
                                        switch value {
                                        case .success( _):
                                            promise(.success(AccountDetails(userUID: user.uid,name: user.displayName, loggedIn: true, premiumUser: false)))
                                        case .failure(let error):
                                            print(error)
                                        }
                                }
                            }
                        case .failure(let error):
                            print(error)
                        }

                }
            } else {
                promise(.success(AccountDetails(userUID: nil, loggedIn: false, premiumUser: false)))
            }
        }.eraseToAnyPublisher()
        )
    }
}
swift firebase future combine publisher
1个回答
0
投票

这就是我想出的:

matt参考:http://www.apeth.com/UnderstandingCombine/operators/operatorsflatmap.html#SECSerializingAsynchronicityhttps://stackoverflow.com/a/60418000/341994

 var handler: AuthStateDidChangeListenerHandle?
 var storage = Set<AnyCancellable>()

    func checkLoginState(completion: @escaping (AnyPublisher<AccountDetails,Error>) -> Void) {
        self.handler = Auth.auth().addStateDidChangeListener { [weak self] auth, user in
            guard let safeSelf = self else { return }
            completion(Future<AccountDetails,Error> { promise in
                if let user = user {
                    safeSelf.handleUserInDatabase(user: user.uid)
                    .sink(receiveCompletion: { completion in
                        if let error = completion.error  {
                            print(error.localizedDescription)
                            promise(.failure(error))
                        }
                    }, receiveValue: { result in
                        if result {
                            promise(.success(AccountDetails(userUID: user.uid,name: user.displayName, loggedIn: true, premiumUser: false)))
                        }
                    }).store(in: &safeSelf.storage)
                } else {
                    promise(.success(AccountDetails(userUID: nil, loggedIn: false, premiumUser: false)))
                }
            }.eraseToAnyPublisher())
        }
    }


    /// Checks if User exists in Firestore, if not creates an empty User and returns true
    private func handleUserInDatabase(user: String) -> AnyPublisher<Bool,Error> {
        return Future<Bool,Error>( { [weak self] promise in
            guard let safeSelf = self else { return }
            safeSelf.checkIfUserIsInDatabase(user: user)
                .flatMap { result -> AnyPublisher<Bool,Error> in
                    if result == false {
                        return safeSelf.createEmptyUser(user: user).eraseToAnyPublisher()
                    } else {
                        promise(.success(true))
                        return Empty<Bool,Error>(completeImmediately: true).eraseToAnyPublisher()
                    }}
                .sink(receiveCompletion: { completion in
                    if let error = completion.error {
                        promise(.failure(error))
                    }}, receiveValue: {promise(.success($0))})
                .store(in:&safeSelf.storage)
            }
        ).eraseToAnyPublisher()
    }
© www.soinside.com 2019 - 2024. All rights reserved.