如果你在 Playground 上运行它:
import Combine
import Foundation
struct User {
let name: String
}
var didAlreadyImportUsers = false
var importUsers: Future<Bool, Never> {
Future { promise in
sleep(5)
promise(.success(true))
}
}
var fetchUsers: Future<[User], Error> {
Future { promise in
promise(.success([User(name: "John"), User(name: "Jack")]))
}
}
var users: AnyPublisher<[User], Error> {
if didAlreadyImportUsers {
return fetchUsers
.receive(on: DispatchQueue.global(qos: .userInitiated))
.eraseToAnyPublisher()
} else {
return importUsers
.receive(on: DispatchQueue.global(qos: .userInitiated))
.setFailureType(to: Error.self)
.combineLatest(fetchUsers)
.map { $0.1 }
.eraseToAnyPublisher()
}
}
users
.receive(on: DispatchQueue.global(qos: .userInitiated))
.sink(receiveCompletion: { completion in
print(completion)
}, receiveValue: { value in
print(value)
})
print("run")
输出将是:
[User(name: "John"), User(name: "Jack")]
run
finished
但我期待得到:
run
[User(name: "John"), User(name: "Jack")]
finished
因为接收器应该在后台线程中运行代码。我在这里缺少什么。
我是否需要 rin 代码:
sleep(5)
promise(.success(true))
在后台线程中?那么这样做的目的是什么
.receive(on: DispatchQueue.global(qos: .userInitiated))
最佳答案
您的 Future 在创建后立即运行,因此在您的情况下,只要访问此属性:
var importUsers: Future<Bool, Never> {
Future { promise in
sleep(5)
promise(.success(true))
}
}
自从
Future
立即运行,这意味着传递给 Promise 的闭包立即执行,使主线程休眠 5 秒,然后继续运行。在你的情况下 Future
访问 users
后立即创建这是在主线程上完成的。receive(on:
影响 sink
的线程(或下游发布者)接收值,而不是创建它们的位置。由于 future 在您调用 .sink
时已经完成,完成和发出的值被传递到 sink
立即地。在后台队列上,但仍然立即。在那之后,你终于点击了
print("run")
线。如果您更换
sleep(5)
有点这个:var importUsers: Future<Bool, Never> {
Future { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 5) {
promise(.success(true))
}
}
}
并对您的订阅代码进行一些小的调整:
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
var cancellables = Set<AnyCancellable>()
users
.receive(on: DispatchQueue.global(qos: .userInitiated))
.sink(receiveCompletion: { completion in
print(completion)
}, receiveValue: { value in
print(value)
}).store(in: &cancellables)
您将看到输出按预期打印,因为最初的 future 不会阻塞主线程五秒钟。
或者,如果您保持 sleep 并像这样订阅,您将看到相同的输出:
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
var cancellables = Set<AnyCancellable>()
users
.subscribe(on: DispatchQueue.global(qos: .userInitiated))
.sink(receiveCompletion: { completion in
print(completion)
}, receiveValue: { value in
print(value)
}).store(in: &cancellables)
原因是你
subscribe
在后台线程上,因此订阅和所有内容都是在主线程之外异步设置的,这会导致 print("run")
在收到 Future
之前运行的结果。然而,当 users
属性被访问(在主线程上),因为那是你初始化 Future
的时候。 .所以整个输出是一次性打印出来的,而不是在 "run"
之后休眠 5 秒。 .
关于ios - 在后台线程中执行组合 future 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62264708/