协调器的 RxSwift 并发问题
RxSwift concurrency problems with coordinator
我想做什么:
- 现在的 VC1
- 当 VC1 被关闭时,出现 VC2
问题:
- 当 VC1 被关闭时,VC2 不存在
脏修复:
设置毫秒延迟。它解决了问题,但想知道为什么会这样
说明:我在 VC1 关闭时收到 viewDidDissapear 事件,因此我可以显示 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
的回调之前,您不应该尝试呈现第二个视图控制器。
无论您在何处关闭视图控制器,请改用下面的代码,并且在可观察对象发出下一个事件之前不要显示下一个视图控制器。
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 { [=11=].connect() }`
*/
func scene<Action>(_ connect: (Self) -> Observable<Action>) -> Scene<Action>
}
struct Scene<Action> {
let controller: UIViewController
let action: Observable<Action>
}
connect
函数是你的视图模型,当它的 Observable 完成或它的订阅者释放时,视图控制器将自动关闭。
presentScene
函数是你的协调者。它处理场景的实际呈现和解散。当您关闭并呈现一个新场景时,它会正确地等待直到前一个视图控制器被关闭,然后再呈现下一个场景。
我想做什么:
- 现在的 VC1
- 当 VC1 被关闭时,出现 VC2
问题:
- 当 VC1 被关闭时,VC2 不存在
脏修复: 设置毫秒延迟。它解决了问题,但想知道为什么会这样
说明:我在 VC1 关闭时收到 viewDidDissapear 事件,因此我可以显示 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
的回调之前,您不应该尝试呈现第二个视图控制器。
无论您在何处关闭视图控制器,请改用下面的代码,并且在可观察对象发出下一个事件之前不要显示下一个视图控制器。
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 { [=11=].connect() }`
*/
func scene<Action>(_ connect: (Self) -> Observable<Action>) -> Scene<Action>
}
struct Scene<Action> {
let controller: UIViewController
let action: Observable<Action>
}
connect
函数是你的视图模型,当它的 Observable 完成或它的订阅者释放时,视图控制器将自动关闭。
presentScene
函数是你的协调者。它处理场景的实际呈现和解散。当您关闭并呈现一个新场景时,它会正确地等待直到前一个视图控制器被关闭,然后再呈现下一个场景。