Ios 在创建可观察/单个时获取传递给subscribeOn()的调度程序
让我展示一个我正在努力解决的问题的简化示例:Ios 在创建可观察/单个时获取传递给subscribeOn()的调度程序,ios,swift,rx-swift,rx-cocoa,Ios,Swift,Rx Swift,Rx Cocoa,让我展示一个我正在努力解决的问题的简化示例: 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
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()
}
}
class服务{
func getCars()->Single{
返回Single.create{observer in
//这里我们使用的线程是在subscribeOn()中定义的。
有人把汽车召回了
//这里我们使用的是主线程,因为有一些回调API实现。
观察员(.success(cars))
}
}
}
}
阶级继承{
func syncCars()->可完成{
return CarService().getCars()
.flatMapCompletable{车辆在
//这里我们使用的是主线程,但我们需要一些后台线程。
储蓄车
}
}
}
类CarViewController{
func装载车(){
CarRepository().syncCars()
.subscribeOn(someBackgroundScheduler)
.observeOn(主线程)
.subscribe()
}
}
从底部:CarViewController
希望从一些外部API同步所有汽车。它定义了与subscribeOn
同步时应使用的线程-我们不想阻止UI线程。不幸的是,在底层,CarService
必须使用一些外部库方法(someCallbackToAPI
),这些方法总是在主线程中返回结果。问题是,在收到结果后,在同一主线程中调用下面的所有方法,例如saveCars
saveCars
可能会阻止UI线程,因为它会将数据保存到数据库中。当然,我可以在CarService().getCars()
和flatMapCompletable
之间的线程之间添加observeOn
,但我希望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()
不是出于测试目的,那么您很可能是做错了什么。嗨,丹尼尔,谢谢您的回答。从架构的角度来看,决定在Alamofire/Moya级别上启动回调的线程并不是一个理想的解决方案。我能想到的唯一解决方案是将调度程序作为参数传递给getCars
方法,并在启动回调后切换到它。顺便说一句,emptysubscribe()
只是一个例子。是的,但根本的问题是Alamofire在后台线程上执行工作,然后切换到主线程以发出结果,然后切换回后台线程以继续处理结果。最好一开始就不要涉及主线。如果Alamofire没有提供这样做的方法,那么就使用URLSession,URLSession是这样做的。