Initial or pre-used cordinators could not be dismissed
berkakkerman opened this issue · 4 comments
I am trying to implemented an app with sign in and sign out flow. Firstly, I have main coordinator(AppCoordinator) like below. AppCoordinator routes to AuthCoordinator first and AuthCoordinator has 3 views;
AuthRoute.login -> AuthRoute.setupName -> AuthRoute.addAccount
After a successful sign in, App routes to HomeCoordinator with a publish subject subscription.
HomeCoordinator is like TabBarCoordinator. In the Profile tab, a sign out button action is available.
HomeRoute
- History
- Payment
- Profile Tab -> triggers HomeRoute. logout
After logout
.multiple(.dismissAll(), .presentFullScreen(self.authCoordinator, animation: .default))
Although I did .dismissAll()
first, the old AuthCoordinator is opening. AuthCoordinator keeps its state. How can I re-create the AuthCoordinator and start it again from a new AuthCoordinator. This issue is happening for the HomeCoordinator.
AppCoordinator is created by a function from AppDelegate.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { setupCoordinator() return true }
AppCoordinator is instantiating with Swinject here.
private func setupCoordinator() { self.appCoordinator = appAssembler.resolver.resolve(AppCoordinator.self)! let router = self.appCoordinator.strongRouter router.setRoot(for: mainWindow) }
AppCoordinator with 3 routes.
class AppCoordinator: NavigationCoordinator<AppRoute> {
private let homeCoordinator: HomeCoordinator
private var authCoordinator: AuthCoordinator
private let introCoordinator: IntroCoordinator
init(homeCoordinator: HomeCoordinator,
authCoordinator: AuthCoordinator,
introCoordinator: IntroCoordinator ) {
self.authCoordinator = authCoordinator
self.homeCoordinator = homeCoordinator
self.introCoordinator = introCoordinator
var initialRoute: AppRoute = .intro
if userDefaultService.isShowIntro {
if sessionService.isTokenValid {
initialRoute = .home
} else {
initialRoute = .auth
}
}
super.init(initialRoute: initialRoute)
self.subscribeToSessionChanges()
}
// MARK: - Overrides
override func prepareTransition(for route: AppRoute) -> NavigationTransition {
switch route {
case .auth:
return .multiple(.dismissAll(), .presentFullScreen(self.authCoordinator, animation: .default))
case .home:
return .multiple(.dismissAll(), .presentFullScreen(self.homeCoordinator, animation: .default))
case .intro:
return .multiple(.dismissAll(), .presentFullScreen(self.introCoordinator, animation: .default))
}
}
private func subscribeToSessionChanges() {
self.sessionService.didSignIn
.subscribe(onNext: { [weak self] _ in
self?.showHome()
})
.disposed(by: self.disposeBag)
self.sessionService.didSignOut
.subscribe(onNext: { [weak self] _ in
self?.showAuth()
})
.disposed(by: self.disposeBag)
}
enum AuthRoute: Route {
case login
case setupName(SetupNameModel)
case setupAccount(AddAccountModel)
case signOut
}
class AuthCoordinator: NavigationCoordinator<AuthRoute> {
// MARK: - Stored properties
// MARK: Initialization
init(initialRoute: AuthRoute = .login) {
super.init(initialRoute: initialRoute)
}
// MARK: Overrides
override func prepareTransition(for route: AuthRoute) -> NavigationTransition {
switch route {
case .login:
let viewController = ModuleBuilder<LoginVC>.buildModule(coordinator: unownedRouter)
return .push(viewController)
return .push(viewController)
case .setupName(let model):
let viewController = ModuleBuilder<SetupNameVC>.buildModule(context: model, coordinator: unownedRouter)
return .push(viewController)
case .setupAccount(let model):
let viewController = ModuleBuilder<AddAccountVC>.buildModule(context: model, coordinator: unownedRouter)
return .push(viewController)
case .signOut:
self.rootViewController.removeFromParent()
return .multiple(.popToRoot(), .dismissAll(), .dismissToRoot(), .dismiss())
}
}
}
class AuthCoordinator: NavigationCoordinator<AuthRoute> {
// MARK: - Stored properties
// MARK: Initialization
init(initialRoute: AuthRoute = .login) {
super.init(initialRoute: initialRoute)
}
// MARK: Overrides
override func prepareTransition(for route: AuthRoute) -> NavigationTransition {
switch route {
case .login:
let viewController = ModuleBuilder<LoginVC>.buildModule(coordinator: unownedRouter)
return .push(viewController)
return .push(viewController)
case .setupName(let model):
let viewController = ModuleBuilder<SetupNameVC>.buildModule(context: model, coordinator: unownedRouter)
return .push(viewController)
case .setupAccount(let model):
let viewController = ModuleBuilder<AddAccountVC>.buildModule(context: model, coordinator: unownedRouter)
return .push(viewController)
case .signOut:
self.rootViewController.removeFromParent()
return .multiple(.popToRoot(), .dismissAll(), .dismissToRoot(), .dismiss())
}
}
}
class HomeCoordinator: TabBarCoordinator<HomeRoute> {
// MARK: Stored properties
private let historyRouter: StrongRouter<HistoryRoute>
private let paymentRouter: StrongRouter<PaymentRoute>
private let profileRouter: StrongRouter<ProfileRoute>
// MARK: Initialization
init(historyCoordinator: HistoryCoordinator,
paymentCoordinator: PaymentCoordinator,
profileCoordinator: ProfileCoordinator) {
self.historyRouter = historyCoordinator.strongRouter
self.paymentRouter = paymentCoordinator.strongRouter
self.profileRouter = profileCoordinator.strongRouter
let homeVC = ModuleBuilder<HomeVC>.buildModule()
super.init(rootViewController: homeVC, tabs: [historyRouter, paymentRouter, profileRouter], select: paymentRouter)
}
// MARK: Overrides
override func prepareTransition(for route: HomeRoute) -> TabBarTransition {
switch route {
case .history:
return .select(historyRouter)
case .payment:
return .select(paymentRouter)
case .profile:
return .select(profileRouter)
}
}
}
enum ProfileRoute: Route {
case logout
}
class ProfileCoordinator: NavigationCoordinator<ProfileRoute> {
// MARK: Initialization
let authCoordinator: AuthCoordinator
init(authCoordinator: AuthCoordinator) {
self.authCoordinator = authCoordinator
super.init(initialRoute: .profile)
}
// MARK: Overrides
override func prepareTransition(for route: ProfileRoute) -> NavigationTransition {
switch route {
case .logout:
return .multiple(.dismissAll(), .dismiss())
}
}
}
@berkakkerman any solution to this ?
@mathemandy Unfortunately, not yet :(
Hey,
each coordinator has a rootViewController (e.g. a UINavigationController
in the case of a NavigationCoordinator
), which it holds strongly. To make sure, that each coordinator is cleaned
, you will have to trigger a route on the AuthCoordinator
that is removing the existing state - or: can you simply create a new instance instead?
@pauljohanneskraft Thank you. It works like a charm right now.