Swift 快速组合异步调用

Swift 快速组合异步调用,swift,async-await,swiftui,combine,Swift,Async Await,Swiftui,Combine,我有以下职能: func getUserProfile() -> AnyPublisher<UserProfileDTO?, Error> { return Future { [unowned self] promise in do { if let data = KeychainWrapper.standard.data(forKey: profileKey) { let profileD

我有以下职能:

    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()
}
func getUserProfile()->AnyPublisher{
返回未来{[无主的自我]承诺
做{
如果let data=KeychainWrapper.standard.data(forKey:profileKey){
让profileDTO=try PropertyListDecoder().decode(UserProfileDTO.self,from:data)
setCurrentSession(profileDTO)
承诺(.success(profileDTO))
}
否则{
承诺(.success(无))
}
}
抓住{
//如果无法解码,请删除当前用户配置文件
let=KeychainWrapper.standard.removeAllKeys()
承诺(失败(错误))
}
}.删除任何发布者()
}
func connect(userProfile:UserProfileDTO)->AnyPublisher{
回报未来{承诺未来}
SBDMain.connect(withUserId:userProfile.email){(user,error)在
如果let error=error{
承诺(失败(错误))
}
否则{
承诺(.success(userProfile))
}
}
}.删除任何发布者()
}
我要做的是首先调用getUserProfile()方法,如果返回值不是nil,则调用connect()方法。但是,如果getUserProfile()具有nil响应,则它不需要调用connect(),而应该只返回nil响应。这两个方法都需要从autoLoginUser()方法调用。 我现在面临的问题是,如何以干净快捷的方式完成这项工作,而不必编写太多嵌套语句

我试着使用平面图,但没有达到我预期的效果。非常感谢您的帮助

我目前正在研究的一个解决方案是。但这不太管用

    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()
}
func autoLoginUser2()->AnyPublisher{
getUserProfile()
.tryMap{[无主的自我]in
如果让currentProfile=$0{
返回连接(用户配置文件:currentProfile)
.tryMap{
//从UserProfile映射到-->UserProfile
返回UserProfileDTOMapper.map($0)
}
}
归零
}.删除任何发布者()
}

通过对已用类型和错误类型进行一些调整,这应该是可行的。首先,您请求配置文件,然后,如果配置文件为零,则强制展开配置文件。如果您抛出一个错误,该错误将作为失败发送到接收器。 如果配置文件存在,请调用connect

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

如果更改connect的签名以返回可选配置文件:

func-connect(userProfile:UserProfileDTO)->AnyPublisher

你可以这样做:

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.

嗨,安德里亚,谢谢你的回答。读完后,我意识到我漏掉了问题的一个重要部分。基本上还有第三种方法,autoLogin(),由视图模型调用。存储库层中有connect()和getUserProfile()。有什么方法可以修改你的答案来适应吗?嗨,卢鲁加,谢谢你的回答。读完后,我意识到我漏掉了问题的一个重要部分。基本上还有第三种方法,autoLogin(),由视图模型调用。存储库层中有connect()和getUserProfile()。有没有办法修改你的答案以适应这个情况?从逻辑上讲,connect()有一个可选参数是没有意义的,因为如果profile中有参数,就不应该调用connect。
getUserProfile()
    .compactMap { $0 }
    .flatMap {
        connect(userProfile: $0)
            .eraseToAnyPublisher()
    }