合并:将 AnyPublisher 转换为另一个 AnyPublisher

Combine: Transform an AnyPublisher into a another AnyPublisher

我想将 Publisher 转换为另一个 Publisher,但出现错误 Cannot convert return expression of type 'AnyPublisher<LoginState, LoginRepositoryError>' to return type 'AnyPublisher<LoginState, Never>'

我的方法可行吗,我有如下代码:

public protocol LoginUseCase {
    func login(email: String, password: String) -> AnyPublisher<Bool, LoginRepositoryError>
}

MyViewmodel.swift

public func login(email: String?, password: String?) -> AnyPublisher<LoginState, Never> {
    guard let email=email, !email.isEmpty else {
        return Just<LoginState>(.invalidEmail).eraseToAnyPublisher()
    }
    guard let password=password, !password.isEmpty else {
        return Just<LoginState>(.invalidPassword).eraseToAnyPublisher()
    }
    
    return loginUseCase.login(email: email, password: password)
        .map { result in
            let subject = PassthroughSubject<LoginState, Never>()
            switch result {
            case .success(_):
                subject.send(.success)
                break
            case .failure(let error):
                switch error {
                case .wrongPassword:
                    subject.send(.wrongPassword)
                case .userNotExist:
                    subject.send(.error)
                case .emailValidationPending:
                    subject.send(.emailValidationPending)
                }
            }
            return subject.eraseToAnyPublisher()
        }.eraseToAnyPublisher()
}

您似乎想使用 catch 运算符将 failure 完成转换为 LoginState

我猜你有这样的enum LoginRepositoryError

public enum LoginRepositoryError: Error {
    case wrongPassword
    case userNotExist
    case emailValidationPending
}

你有这样的enum LoginState

public enum LoginState {
    case success
    case invalidEmail
    case invalidPassword
    case wrongPassword
    case error
    case emailValidationPending
}

由于您想将错误转换为 LoginStates,让我们添加一个初始化程序来执行此操作:

extension LoginState {
    public init(_ repoError: LoginRepositoryError) {
        switch repoError {
        case .wrongPassword: self = .wrongPassword
        case .userNotExist: self = .error
        case .emailValidationPending: self = .emailValidationPending
        }
    }
}

并且由于 LoginUseCase.loginOutputBool,我们还要添加一个初始化程序以将 Bool 转换为 LoginState:

extension LoginState {
    public init(success: Bool) {
        self = success ? .success : .error
    }
}

现在我们可以将这些初始值设定项与 mapcatch 运算符一起使用来创建您正在寻找的 AnyPublisher<LoginState, Never>

extension LoginUseCase {
    public func loginState(withEmail email: String?, password: String?) -> AnyPublisher<LoginState, Never> {
        guard let email=email, !email.isEmpty else {
            return Just<LoginState>(.invalidEmail).eraseToAnyPublisher()
        }
        guard let password=password, !password.isEmpty else {
            return Just<LoginState>(.invalidPassword).eraseToAnyPublisher()
        }

        return login(email: email, password: password)
            .map { LoginState(success: [=14=]) }
            .catch { Just(LoginState(error: [=14=])) }
            .eraseToAnyPublisher()
    }
}