简体   繁体   English

Swift 组合 - 异步调用

[英]Swift Combine - Async calls

I have the following functions:我有以下功能:

    func getUserProfile() -> AnyPublisher<UserProfileDTO?, Error> {
    return Future { [unowned self] promise in
        do {
            if let data = KeychainWrapper.standard.data(forKey: profileKey) {
                let profileDTO = try PropertyListDecoder().decode(UserProfileDTO.self, from: data)
                setCurrentSession(profileDTO)
                promise(.success(profileDTO))
            }
            else {
                promise(.success(nil))
            }
        }
        catch {
            // Delete current UserProfile if cannot decode
            let _ = KeychainWrapper.standard.removeAllKeys()
            promise(.failure(error))
        }
    }.eraseToAnyPublisher()
}

    func connect(userProfile: UserProfileDTO) -> AnyPublisher<UserProfileDTO, Error> {
    return Future { promise in
        SBDMain.connect(withUserId: userProfile.email) { (user, error) in
            if let error = error {
                promise(.failure(error))
            }
            else {
                promise(.success(userProfile))
            }
        }
    }.eraseToAnyPublisher()
}

What I want to do is to first call the getUserProfile() method and if the return value in not nil then call the connect() method.我想要做的是首先调用 getUserProfile() 方法,如果返回值不是 nil 则调用 connect() 方法。 However, if the getUserProfile() has nil response it does not need to call the connect() and it should just return the nil response.但是,如果 getUserProfile() 有 nil 响应,它不需要调用 connect() 并且它应该只返回 nil 响应。 Both these methods needs to be called from the autoLoginUser() method.这两个方法都需要从 autoLoginUser() 方法中调用。 The problem I'm having right now is figuring out how to do this in a clean swift way without writing too much nested statements.我现在遇到的问题是弄清楚如何以干净的 swift 方式执行此操作,而无需编写太多嵌套语句。

I tried to use flatMaps but it didn't workout the way I expected.我尝试使用 flatMaps,但它并没有按我预期的方式锻炼。 Any help is much appreciated.任何帮助深表感谢。

A solution I've been working on at the moment is this.我目前一直在研究的一个解决方案是这个。 But it doesn't quite work.但这并不完全奏效。

    func autoLoginUser2() -> AnyPublisher<UserProfile?,Error> {
    getUserProfile()
        .tryMap { [unowned self] in
            if let currentProfile = $0 {
                return connect(userProfile: currentProfile)
                    .tryMap {
                        //Map from UserProfileDTO --> UserProfile
                        return UserProfileDTOMapper.map($0)
                        
                    }
            }
            return nil
        }.eraseToAnyPublisher()
}

With some adjustment for used types and error types this should work.通过对使用的类型和错误类型进行一些调整,这应该可以工作。 First you ask for the profile, then you force unwrap the profile if it is nil you throw an error that will be sent to the sink as a failure.首先,您要求提供配置文件,然后强制打开配置文件,如果它为 nil,您将抛出一个错误,该错误将作为失败发送到接收器。 If the profile is present you call connect.如果配置文件存在,则调用 connect。

getUserProfile()
.tryMap { userDTO -> UserProfileDTO in
    if let id = userDTO {
        return id
    }
    throw MyError.noProfileDT
}
.flatMap { id in
    connect(id)
}
.sink {
    //.....
}

If you change the signature of connect to return Optional profile:如果您更改连接的签名以返回可选配置文件:

func connect(userProfile: UserProfileDTO) -> AnyPublisher<UserProfileDTO?, Error>

You could do something like this:你可以这样做:

getUserProfile()
    .flatMap { userProfile -> AnyPublisher<UserProfileDTO?, Error> in
            
        if let userProfile = userProfile {
            return connect(userProfile: userProfile)
                .eraseToAnyPublisher()
        } else {
            return Just<UserProfileDTO?>(nil)
                .setFailureType(to: Error.self)
                .eraseToAnyPublisher()
        }
    }
    //.sink etc.

If you don't need the publisher to emit nil, you could leave the connect signature as is and use compactMap :如果您不需要发布者发出 nil,您可以保留连接签名并使用compactMap

getUserProfile()
    .compactMap { $0 }
    .flatMap {
        connect(userProfile: $0)
            .eraseToAnyPublisher()
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM