我有一个应用程序使用 MVP
与 Coordinator
图案。
当子协调器发送事件时,我希望我的 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 ?
最佳答案
coordinateToRoot
与 AppCoordinator.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/