首页 > 解决方案 > 如何链接 Swift Futures

问题描述

我定义了以下功能:

func createAccessControl() -> Future<SecAccessControl, Error>

func evaluatePolicy(context: LAContext, localizedReason: String) -> Future<LAContext, Error>

func evaluateAccessControl(
    context: LAContext,
    accessControl: SecAccessControl,
    operation: LAAccessControlOperation,
    localizedReason: String
) -> Future<LAContext, Error>

func copy(query: [String: Any]) -> Future<Data, Error>

我想像这样将它们链接在一起:

func load(key: String, context: LAContext = LAContext(), localizedReason: String) -> Future<Data, Error> {
        createAccessControl().flatMap { accessControl in
            evaluatePolicy(context: context, localizedReason: localizedReason)
                .flatMap { context in
                    evaluateAccessControl(context: context, accessControl: accessControl, operation: .useItem, localizedReason: localizedReason)
                }
                .flatMap { context in
                    copy(query: [
                        kSecClass as String: kSecClassGenericPassword as String,
                        kSecAttrService as String: service,
                        kSecAttrAccount as String: account,
                        kSecAttrAccessControl as String: accessControl,
                        kSecUseAuthenticationContext as String: context,
                        kSecReturnData as String: kCFBooleanTrue,
                        kSecMatchLimit as String: kSecMatchLimitOne,
                    ])
                }
        }
    }

但是,我收到此错误:

Cannot convert return expression of type 'Publishers.FlatMap<Publishers.FlatMap<Future<Data, Error>, Publishers.FlatMap<Future<LAContext, Error>, Future<LAContext, Error>>>, Future<SecAccessControl, Error>>' to return type 'Future<Data, Error>'

我认为flatMap应该使结果类型变平,但这似乎并没有像我预期的那样发生。

我如何将期货链接在一起,类似于 JavaScript 的“then”?

标签: swiftfunctional-programmingcombine

解决方案


将我的返回类型从 更改Future<>AnyPublisher<>消除了所有编译器错误,并且只需要调用eraseToAnyPublisher()这些函数内部。例如:

func evaluateAccessControl(context: LAContext, accessControl: SecAccessControl, operation: LAAccessControlOperation, localizedReason: String) -> AnyPublisher<LAContext, Error> {
    Future() { promise in
        context.evaluateAccessControl(accessControl, operation: operation, localizedReason: localizedReason) { success, error in
            if let error = decodeLAError(error) {
                promise(.failure(error))
            } else if success {
                promise(.success(context))
            }
        }
    }.eraseToAnyPublisher()
}

推荐阅读