gpt4 book ai didi

swift - RxSwift 主题在调用时不触发事件

转载 作者:行者123 更新时间:2023-12-04 11:45:39 25 4
gpt4 key购买 nike

我有一个应用程序使用 MVPCoordinator图案。

当子协调器发送事件时,我希望我的 AppCoordinator递归调用一个方法,根据一些 SessionState 选择下一个协调器.

该应用程序的基本流程如下 -
AppCoordinator

  • start()调用 coordinateToRoot具有初始状态
  • 订阅 showStartScene()启动子协调器
  • StartCoordinator
  • start()创建 MVP模块现在对用户可见
  • MVP模块调用 AuthSvc它对 iDP 进行异步调用并确认身份验证状态
  • 完成此任务后,发布由 AppCoordinator 中的订阅获取的事件。的 coordinateToRoot方法和循环使用适当的 View 状态的协调器重复。

  • 然而,问题是在该事件发布时,什么也没有发生。 start()没有显示它收到了事件和 coordinateToRoot不再被调用。

    我在下面创建了最基本的版本来演示这一点。我也硬编码了 showStartScene返回 .signedIn而不是查找身份验证状态。

    在下面的示例中,我希望一旦加载 View , presenter.signal应该立即发出导致打印语句显示的事件。

    session 状态

    enum SessionState: String {
    case unknown, signedIn, signedOut
    }

    应用协调员

    final class AppCoordinator: BaseCoordinator<Void> {

    private let window: UIWindow

    init(window: UIWindow) {
    self.window = window
    }

    override func start() -> Observable<Void> {
    coordinateToRoot(basedOn: .unknown)
    return .never()
    }

    /// Recursive method that will restart a child coordinator after completion.
    /// Based on:
    /// https://github.com/uptechteam/Coordinator-MVVM-Rx-Example/issues/3
    private func coordinateToRoot(basedOn state: SessionState) {

    switch state {
    case .unknown:
    return showStartScene()
    .subscribe(onNext: { [unowned self] state in
    self.window.rootViewController = nil
    self.coordinateToRoot(basedOn: state)
    })
    .disposed(by: disposeBag)

    case .signedIn:
    print("I am signed in")

    case .signedOut:
    print("I am signed out")
    }
    }

    private func showStartScene() -> Observable<SessionState> {
    let coordinator = StartCoordinator(window: window)
    return coordinate(to: coordinator).map { return .signedIn }
    }
    }

    启动协调器

    final class StartCoordinator: BaseCoordinator<Void> {

    private(set) var window: UIWindow

    init(window: UIWindow) {
    self.window = window
    }

    override func start() -> Observable<CoordinationResult> {

    let viewController = StartViewController()
    let presenter = StartPresenter(view: viewController)

    viewController.configurePresenter(as: presenter)

    window.rootViewController = viewController
    window.makeKeyAndVisible()

    return presenter.signal
    }
    }

    启动 MVP 模块

    protocol StartViewInterface: class {
    func configurePresenter(as presenter: StartPresentation)
    }

    protocol StartPresentation: class {
    var viewIsReady: PublishSubject<Void> { get }
    var signal: PublishSubject<Void> { get }
    }
    // MARK:- StartPresenter
    final class StartPresenter {

    // Input
    let viewIsReady = PublishSubject<Void>()

    // Output
    let signal = PublishSubject<Void>()

    weak private var view: StartViewInterface?

    private lazy var disposeBag = DisposeBag()

    init(view: StartViewInterface?) {
    self.view = view

    viewIsReady.bind(to: signal).disposed(by: disposeBag)
    }

    }

    extension StartPresenter: StartPresentation { }

    // MARK:- StartViewController
    final class StartViewController: UIViewController {

    private var presenter: StartPresentation?

    override func viewDidLoad() {
    super.viewDidLoad()

    if let presenter = presenter {
    presenter.viewIsReady.onNext(())
    }

    }
    }

    extension StartViewController: StartViewInterface {
    func configurePresenter(as presenter: StartPresentation) {
    self.presenter = presenter
    }
    }



    有趣的是,如果我在 StartCoordinator 中做这样的事情该过程确实有效,但它没有达到我想要实现的目标。

        override func start() -> Observable<CoordinationResult> {

    let viewController = StartViewController()
    let presenter = StartPresenter(view: viewController)

    viewController.configurePresenter(as: presenter)

    window.rootViewController = viewController
    window.makeKeyAndVisible()


    let subject = PublishSubject<Void>()


    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    subject.onNext(())
    }

    return subject
    }

    供引用我的 BaseCoordinator好像 -

    /// Base abstract coordinator generic over the return type of the `start` method.
    class BaseCoordinator<ResultType>: CoordinatorType {

    /// Typealias which allows to access a ResultType of the Coordainator by `CoordinatorName.CoordinationResult`.
    typealias CoordinationResult = ResultType

    /// Utility `DisposeBag` used by the subclasses.
    let disposeBag = DisposeBag()

    /// Unique identifier.
    internal let identifier = UUID()

    /// 1. Stores coordinator in a dictionary of child coordinators.
    /// 2. Calls method `start()` on that coordinator.
    /// 3. On the `onNext:` of returning observable of method `start()` removes coordinator from the dictionary.
    ///
    /// - Parameter coordinator: Coordinator to start.
    /// - Returns: Result of `start()` method.
    func coordinate<T: CoordinatorType, U>(to coordinator: T) -> Observable<U> where U == T.CoordinationResult {
    store(coordinator: coordinator)
    return coordinator.start()
    .do(onNext: { [weak self] _ in self?.free(coordinator: coordinator) })
    }

    /// Starts job of the coordinator.
    ///
    /// - Returns: Result of coordinator job.
    func start() -> Observable<ResultType> {
    fatalError(message: "Start method should be implemented.")
    }

    /// Dictionary of the child coordinators. Every child coordinator should be added
    /// to that dictionary in order to keep it in memory.
    /// Key is an `identifier` of the child coordinator and value is the coordinator itself.
    /// Value type is `Any` because Swift doesn't allow to store generic types in the array.
    private(set) var childCoordinators: [UUID: Any] = [:]

    /// Stores coordinator to the `childCoordinators` dictionary.
    ///
    /// - Parameter coordinator: Child coordinator to store.
    private func store<T: CoordinatorType>(coordinator: T) {
    childCoordinators[coordinator.identifier] = coordinator
    }

    /// Release coordinator from the `childCoordinators` dictionary.
    ///
    /// - Parameter coordinator: Coordinator to release.
    private func free<T: CoordinatorType>(coordinator: T) {
    childCoordinators[coordinator.identifier] = nil
    }
    }


    编辑
    我添加了一些 debug运算符(operator),我可以看到下一个事件和订阅的订单显示关闭
    2019-11-08 10:26:19.289: StartPresenter -> subscribed
    2019-11-08 10:26:19.340: StartPresenter -> Event next(())
    2019-11-08 10:26:19.350: coordinateToRoot -> subscribed

    为什么是 coordinateToRoot订阅后 StartPresenter被 build ?

    最佳答案

    coordinateToRootAppCoordinator.start(_:) 返回的 Observable 的生命周期无关.这意味着无法保证 coordinateToRoot 的顺序。和 StartPresenter已订阅。
    为了保证顺序,我觉得你可以用do运算符并为 onSubscribe 传递闭包争论。此 onSubscribe闭包将在订阅底层 observable 之前运行。
    这是我认为你可以做出的改变:

    final class AppCoordinator: BaseCoordinator<Void> {

    override func start() -> Observable<Void> {
    return Observable<Void>.never().do(onSubscribe: { [weak self] _ in
    self?.coordinateToRoot(basedOn: .unknown)
    })
    }
    }

    关于swift - RxSwift 主题在调用时不触发事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58764341/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com