how to use Publishers.CombineLatest to get 1 publisher

杀马特。学长 韩版系。学妹 提交于 2021-01-05 07:18:48

问题


I am trying to use 2 publishers and have them stream to 1 publisher that is mapped from both values.

My code is:

class ViewModel {

    let email = CurrentValueSubject<String, Never>("")

    lazy var isEmailValid = email.map { self.validateEmail(email: $0) }

    let password = CurrentValueSubject<String, Never>("")

    lazy var isPasswordCorrect = password.map {
        self.validatePassword(password: $0)
    }

    let canLogin: CurrentValueSubject<Bool, Never>

    private func validateEmail(email: String) -> Bool {
        return email == "1234@gmail.com"
    }

    private func validatePassword(password: String) -> Bool {
        return password == "1234"
    }


    init() {
    
        canLogin = Publishers
            .CombineLatest(isEmailValid, isPasswordCorrect)
            .map { $0 && $1 } 

    }
}

Then in the init I get this error:

    //error: Cannot assign value of type 
'Publishers.Map<Publishers.CombineLatest<Publishers.Map<CurrentValueSubject<String, Never>, 
Bool>, Publishers.Map<CurrentValueSubject<String, Never>, Bool>>, Bool>' to type 'CurrentValueSubject<Bool, Never>'

I am new to combine so I find it a little confusing. How should I achieve, from the code above, the combination of 2 publishers isEmailValid and isPasswordCorrect, into 1 publisher that is a CurrentValueSubject<Bool, Never>?


回答1:


A CurrentValueSubject is:

A subject that wraps a single value and publishes a new element whenever the value changes.

Your canLogin is certainly not a CurrentValueSubject. It is the result of combining two other publishers with the CombineLatest operator, and then mapping the combined publisher to yet another publisher.

In the language of the Swift type system, this kind of publisher is called:

Publishers.Map<Publishers.CombineLatest<Publishers.Map<CurrentValueSubject<String, Never>, Bool>, Publishers.Map<CurrentValueSubject<String, Never>, Bool>>, Bool>

Obviously, no one would declare a property with a type like that, so we use eraseToAnyPublisher to get ourselves an AnyPublisher, to say that we don't actually care what type of publisher it is.

let canLogin: AnyPublisher<Bool, Never>

...

canLogin = Publishers
        .CombineLatest(isEmailValid, isPasswordCorrect)
        .map { $0 && $1 } 
        .eraseToAnyPublisher()



回答2:


You've declared the type of canLogin completely incorrectly.

It needs to be an AnyPublisher, which you can get by simply calling eraseToAnyPublisher on the map.

lazy var canLogin: AnyPublisher<Bool, Never> = isEmailValid.combineLatest(isPasswordCorrect).map { $0 && $1 }.eraseToAnyPublisher()


来源:https://stackoverflow.com/questions/65072163/how-to-use-publishers-combinelatest-to-get-1-publisher

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!