RxSwift 和 MVVM:observable 在没有绑定的情况下无法执行
Posted
技术标签:
【中文标题】RxSwift 和 MVVM:observable 在没有绑定的情况下无法执行【英文标题】:RxSwift and MVVM: observable not executing without binding 【发布时间】:2017-09-18 18:24:32 【问题描述】:我是 RxSwift 的新手,正在尝试使用 MVVM 架构实现应用程序。我有视图模型:
class CategoriesViewModel
fileprivate let api: APIService
fileprivate let database: DatabaseService
let categories: Results<Category>
// Input
let actionRequest = PublishSubject<Void>()
// Output
let changeset: Observable<(AnyRealmCollection<Category>, RealmChangeset?)>
let apiSuccess: Observable<Void>
let apiFailure: Observable<Error>
init(api: APIService, database: DatabaseService)
self.api = api
self.database = database
categories = database.realm.objects(Category.self).sorted(byKeyPath: Category.KeyPath.name)
changeset = Observable.changeset(from: categories)
let requestResult = actionRequest
.flatMapLatest [weak api] _ -> Observable<Event<[Category]>> in
guard let strongAPI = api else
return Observable.empty()
let request = APIService.MappableRequest(Category.self, resource: .categories)
return strongAPI.mappedArrayObservable(from: request).materialize()
.shareReplayLatestWhileConnected()
apiSuccess = requestResult
.map $0.element
.filterNil()
.flatMapLatest [weak database] newObjects -> Observable<Void> in
guard let strongDatabase = database else
return Observable.empty()
return strongDatabase.updateObservable(with: newObjects)
apiFailure = requestResult
.map $0.error
.filterNil()
我在视图控制器中有以下绑定:
viewModel.apiSuccess
.map _ in false
.bind(to: refreshControl.rx.isRefreshing)
.disposed(by: disposeBag)
viewModel.apiFailure
.map _ in false
.bind(to: refreshControl.rx.isRefreshing)
.disposed(by: disposeBag)
但如果我评论绑定,数据库更新部分将停止执行。我需要让它执行,而不是在视图模型中使用 dispose bag。有可能吗?
还有一点额外的问题:我应该像在我的视图模型代码中那样使用 api
/database
和 return Observable.empty()
的弱强舞蹈,还是我可以安全地使用 unowned api
/unowned database
?
谢谢。
更新:
APIService 中返回 observable 的函数:
func mappedArrayObservable<T>(from request: MappableRequest<T>) -> Observable<[T]>
let jsonArray = SessionManager.jsonArrayObservable(with: request.urlRequest, isSecured: request.isSecured)
return jsonArray.mapResponse(on: mappingSheduler, Mapper<T>().mapArray(JSONArray: $0) )
【问题讨论】:
【参考方案1】:除非有订阅者准备好接收结果,否则工作不会完成。
您的 DatabaseService 需要有一个 dispose 包并订阅 Observable<[Category]>
。比如:
class ProductionDatabase: DatabaseService
var categoriesUpdated: Observable<Void> return _categories
func updateObservable(with categories: Observable<[Category]>)
categories
.subscribe(onNext: [weak self] categories in
// store categories an then
self?._categories.onNext()
)
.disposed(by: bag)
private let _categories = PublishSubject<Void>()
private let bag = DisposeBag()
然后apiSuccess = database.categoriesUpdated
和database.updateObservable(with: requestResult.map $0.element .filterNil())
【讨论】:
谢谢!但是我可以在订阅时使用unowned self
而不是[weak self]
吗?似乎订阅 self
拥有的 disposeBag
在 self
取消初始化后无法调用,但我不确定。或者可以订阅块开始执行,在后台保存工作,并在self
被释放后到达self?._categories.onNext()
?
只使用unowned
,如果你知道self将在程序的生命周期中存在,你知道订阅只会被调用一次,或者订阅闭包正在做一些会导致@987654333的事情@要删除,否则使用weak
。顺便说一句,您也可以使用 APIService
执行上述操作,然后您的视图模型将只包含逻辑。
你的意思是我应该订阅 api 服务中的actionRequest
并从基础主题返回对象,就像在数据库示例中一样?但是我有返回 observable 的通用函数(见更新的答案),我不清楚如果我将从 APIService
的同一实例中执行两个具有不同返回类型的请求,它将如何工作@
如果将 PublishSubject
实例传递给具有 observable 的服务方法并在其上调用 onNext(:_)
而不是使用像 private let _categories = PublishSubject<Void>()
这样的属性,它将起作用。所以编译器会推断返回类型,每个订阅都会有自己的主题通知。
我想说的是,您只提到了模型的一个输入,但您也有来自 api 服务和数据库的输入。将它们建模为第一类输入而不是将它们埋在 flatMaps 中会很有帮助。如何(或是否)你想这样做取决于你。以上是关于RxSwift 和 MVVM:observable 在没有绑定的情况下无法执行的主要内容,如果未能解决你的问题,请参考以下文章
RxSwift:多次连接到 Connectable Observable
RxSwift 从 Observable 序列中的一项获取值