4

我在这部分代码上有一些崩溃:

SRNetwork.provider
        .request(SRService.postData(user_id: userId))
        .mapArray(STrain.self)
        .observeOn(ConcurrentDispatchQueueScheduler.init(queue: SDispatchQueue.dataTrain.getQueue()))
        .subscribe({ (event) -> Void in
            switch event {
            case .next(let response):
                self.train.value = response
                SRealmTrain.sharedInstance.cacheTrain(response)
            case .error(let error):
                SRealmTrain.sharedInstance.fetchTrainRx(userId) //CRASH IS HERE
                    .bindTo(self.train)
                    .addDisposableTo(self.disposeBag)
                print("\(error)")
            default: break;
            }
        })
        .addDisposableTo(disposeBag);

我认为问题在于我不在MainScheduler.instancerxRealm 上,main thread但我不想要它。有可能修复它吗?

fetchTrainRx

public func fetchTrainRx(_ userId: String) -> Observable<[STrain]> {

    let predicate = NSPredicate(format: "userId == %@", userId)

    if let realm = realm {

        return Observable.from(realm
            .objects(SRTrain.self)
            .filter(predicate)
            .sorted(byProperty: "order", ascending: true))
            .map ({
                $0.map(STrain.init)
        })
    }
    return Observable.just([]);
}
4

1 回答 1

9

Realm 的通知默认在主线程(安装应用程序的默认运行循环的位置)上传递。这就是为什么在您的代码中会出现“只能从运行循环中添加通知块”异常的原因,因为您尝试在没有运行循环的后台线程中订阅通知。

当您使用时Observable.from( ... some realm collection ... ),RxRealm 订阅 Realm 本身发送的通知,此时您会收到异常,因为您的代码显式切换到此行上的后台线程.observeOn(ConcurrentDispatchQueueScheduler.init(queue...

您可以采用两种不同的方式来解决您当前的问题:

1)不要在您的subscribe操作员之前切换到后台队列(假设您正在主线程上进行 Rx 订阅)

2)在您的fetchTrainRx方法内部DispatchQueue.main.sync,用于在主线程上创建 Observable。

这应该可以解决您当前的问题。

无论如何-从您的代码中,我看到您将 Realm 引用存储在类中的某个位置(或者至少看起来您这样做),这不是最佳实践。如果您正在处理不同的线程,请使用let realm = try! Realm()每次在当前线程上获取 Realm 引用;这将确保您始终使用正确的领域实例。

于 2017-01-03T15:50:28.083 回答