让我显示一个我正在苦苦挣扎的问题的简化示例:
class CarService {
func getCars() -> Single<[Car]> {
return Single.create { observer in
// Here we're using a thread that was defined in subscribeOn().
someCallbackToAPI { cars in
// Here we're using main thread, because of the someCallbackToAPI implementation.
observer(.success(cars))
}
}
}
}
class CarRepository {
func syncCars() -> Completable {
return CarService().getCars()
.flatMapCompletable { cars in
// Here we're using main thread, but we want some background thread.
saveCars(cars)
}
}
}
class CarViewController {
func loadCar() {
CarRepository().syncCars()
.subscribeOn(someBackgroundScheduler)
.observeOn(MainThread)
.subscribe()
}
}
从底部开始:
CarViewController
想要从某个外部API同步所有汽车。它定义了用于与subscribeOn
同步的线程-我们不想阻止UI线程。不幸的是,在下面,CarService
必须使用一些外部库方法(someCallbackToAPI
),这些方法总是在主线程中返回结果。问题在于,接收到结果后,下面的所有方法(例如saveCars
在同一主线程中调用。 saveCars
可能会阻止UI线程,因为它会将数据保存到数据库中。当然,我可以在observeOn
和CarService().getCars()
之间的线程之间添加flatMapCompletable
,但是我希望CarRepository
被转储并且不了解线程。定义工作线程是CarViewController
的责任。所以我的问题是,这是我可以通过
subscribeOn
方法传递调度程序并在从someCallbackToApi
接收到结果之后切换回调度程序的一种方法吗? 最佳答案
最简洁的答案是不。
正如您所猜测的那样,问题在于您的someCallbackToAPI
正在路由到主线程,这不是您想要的,并且您无能为力,只需重写someCallbackToAPI。如果您使用的是Alamofire或Moya,我认为它们还有其他方法,它们不会在主线程上调用闭包,但我不确定。 URLSession不会切换到主线程,因此一种想法是改为使用它。
如果要让saveCars
在后台线程上发生,则必须使用observeOn将计算从main推回到后台线程上。 subscribeOn
唯一会做的就是在后台线程上调用someCallbackToAPI(_:)
,它无法决定函数将在哪个线程上调用其闭包。
所以像这样:
func syncCars() -> Completable {
return CarService().getCars()
.observeOn(someBackgroundScheduler)
.flatMapCompletable { cars in
// Now this will be on the background thread.
saveCars(cars)
}
}
最后一点,空订阅是一种代码味道。每当您发现自己出于测试目的以外的其他目的调用
.subscribe()
时,您可能都会做错事情。关于ios - 在创建Observable/Single时将传递给ScheduleOn的调度程序,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60095172/