如何在 AnyPublisher 中包装一个异步函数?

How to wrap an async function inside AnyPublisher?

假设我想创建一个调用一些随机 API 和 returns 随机 Int 的异步函数。我想用 future

包装它
func createFuture() -> Future<Int, Never> {
  return Future { promise in
    promise(.success(Int.random(1...10))
  }
}

这将 return 我每次都得到相同的输出。相反,我想 return AnyPublisher.

func createAnyPublisher() -> AnyPublisher<Int, Never> {  //This is invalid
    return AnyPublisher<Int, Never> { seed in
        seed.success(Int.random(in: 1...10))
    }
}

一个更好的例子:

func guessNumber(num: Int) -> AnyPublisher<Bool, Never> {
    asyncRandomNumber { winner in
        if num == winner {
            // return true
        } else {
            // return false
        }
    }
}

private func asyncRandomNumber(completion: (Int) -> Void) {
    completion(Int.random(in: 1...10))
}

如何包装 asyncRandomNumber ?

Future 在初始化时缓存它的结果,这就是为什么你总是看到相同的结果。如果您希望每个订阅者收到不同的随机数,您可以使用 Just

func randomIntPublisher() -> AnyPublisher<Int, Never> {
    Just(Int.random(in: 1...10)).eraseToAnyPublisher()
}

如果您想在 Publisher 中包装一个异步函数,您可以使用 Future,只需确保每次在创建新订阅之前调用您的函数 - 这将确保您创建了一个新的 Future,因此结果不会被缓存并在不同的订阅者之间共享。

func asyncRandomNumber(completion: @escaping (Int) -> Void) {
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion(Int.random(in: 1...100))
    }
}

func asyncRandomNumber() -> AnyPublisher<Int, Never> {
    Future { promise in
        asyncRandomNumber(completion: { num in
            promise(.success(num))
        })
    }.eraseToAnyPublisher()
}

asyncRandomNumber().sink(receiveValue: { print("First subscription received \([=11=])") }).store(in: &subscriptions)
asyncRandomNumber().sink(receiveValue: { print("Second subscription received \([=11=])") }).store(in: &subscriptions)