让我显示一个我正在苦苦挣扎的问题的简化示例:

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线程,因为它会将数据保存到数据库中。当然,我可以在observeOnCarService().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/

10-09 22:35