RxSwift并发问题协调员

问题描述

我想做的事情内容

  1. 当前VC1
  2. 当VC1被驳回,本VC2

问题

  1. 当VC1被驳回,VC2不存在

脏修复: 把milisecond延迟。它解决了这个问题,但想知道为什么会发生

解释:我得到viewDiddissapear事件时VC1驳回所以可以呈现VC2

如果您需要更多的细节,请询问。

代码

class viewmodel {

    let coordinator = Coordinator()

    struct Input {
        let itemSelected: Driver<IndexPath>
    }

    struct Output {
        let presentVC1: Driver<Void>
        let presentVC2: Driver<Void>
    }

    func transform(input: Input) -> Output {

        let navigatetoVC1 = input.itemSelected
            .flatMap { [coordinator] in
                return coordinator.transition(to: Scene.VC1)
            }

        let navigatetoVC2 = navigatetoVC1
            .delay(.milliseconds(1))
            .flatMap { [coordinator] in
                return coordinator.transition(to: Scene.VC2)
            }

        return Output(presentVC1: presentVC1,presentVC2: presentVC2)
    }

协调员代码

func transition(to scene: TargetScene) -> Driver<Void> {
        let subject = PublishSubject<Void>()

        switch scene.transition {
           
            case let .present(viewController):
                _ = viewController.rx
                    .sentMessage(#selector(UIViewController.viewDiddisappear(_:)))
                    .map { _ in } 
                    .bind(to:subject)
                currentViewController.present(viewController,animated: true)
                
        return subject
            .take(1)
            .asDriverOnErrorJustComplete()
    }

解决方法

在完全关闭视图控制器之前调用 viewDidDisappear 方法。在调用 dismiss 的回调之前,您不应尝试呈现第二个视图控制器。

无论您在哪里关闭视图控制器,请改用下面的代码,并且在 observable 发出下一个事件之前不要显示下一个视图控制器。

extension Reactive where Base: UIViewController {
    func dismiss(animated: Bool) -> Observable<Void> {
        Observable.create { [base] observer in
            base.dismiss(animated: animated) {
                observer.onNext(())
                observer.onCompleted()
            }
            return Disposables.create()
        }
    }
}

我建议您考虑使用我的因果逻辑效果架构,其中包含正确处理视图控制器呈现和关闭所需的一切。

https://github.com/danielt1263/CLE-Architecture-Tools

部分界面如下:

/**
Presents a scene onto the top view controller of the presentation stack. The scene will be dismissed when either the action observable completes/errors or is disposed.
- Parameters:
- animated: Pass `true` to animate the presentation; otherwise,pass `false`.
- sourceView: If the scene will be presented in a popover controller,this is the view that will serve as the focus.
- scene: A factory function for creating the Scene.
- Returns: The Scene's output action `Observable`.
*/
func presentScene<Action>(animated: Bool,overSourceView sourceView: UIView? = nil,scene: @escaping () -> Scene<Action>) -> Observable<Action>

extension NSObjectProtocol where Self : UIViewController {

    /**
        Create a scene from an already existing view controller.
    
        - Parameter connect: A function describing how the view controller should be connected and returning an Observable that emits any data the scene needs to communicate to its parent.
        - Returns: A Scene containing the view controller and return value of the connect function.
    
        Example:
    
        `let exampleScene = ExampleViewController().scene { $0.connect() }`
        */
    func scene<Action>(_ connect: (Self) -> Observable<Action>) -> Scene<Action>
}

struct Scene<Action> {
    let controller: UIViewController
    let action: Observable<Action>
}

connect 函数是您的视图模型,当其 Observable 完成或订阅者处置时,视图控制器将自动关闭。

presentScene 函数是您的协调器。它处理场景的实际呈现和消除。当您关闭并呈现一个新场景时,它会正确处理等待直到前一个视图控制器被关闭,然后再呈现下一个。