Search code examples
swiftrx-swiftrx-cocoa

Make RxCocoa binding for UIPageViewController.setViewControllers (how to synchronize Observable)


currently, I want to bind the value of Observable<UIViewController> to my UIPageViewController. Initial idea is simple and straightforward:

viewControllerObservable
    .subscribe(onNext: { [weak self] viewController in

        self?.pageVC.setViewControllers([viewController], 
                                        direction: .forward, 
                                        animated: false, 
                                        completion: nil)
     })
    .disposed(by: disposeBag)

but if values in viewControllerObservable changes too quick, page view controller receives new set command before it's done with adding previous view controller and I'm getting NSInternalInconsistencyException.

I can make that code more "reactive", using Binder, but I'll still face the same problem.

Pretty obvious way here is to use throttle, but it seems to be pretty dirty fix, masking problem, not fixing it.

Ideally, I need some way to hold further values handling until completion is called in setViewControllers.

How can I achieve that?


Solution

  • So, best solution I've come so far, is to use second observable for the purpose of sync.

    let sync = BehaviorSubject<Void>(value: ())
    
    Observable.zip(pageProvider.selectedViewControllerObservable, sync)
        .subscribe(onNext: { [weak self] viewController, _ in
            self?.pageVC.setViewControllers([viewController],
                                            direction: .forward,
                                            animated: false,
                                            completion: {sync.onNext()})
        })
        .disposed(by: disposeBag)
    

    As Observable.zip waits for both observables to emit value, it will be "locked" until sync will receive next value.