【问题标题】:Swift: How to use Xcoordinator to set a root view controller from child coordinator?Swift:如何使用 Xcoordinator 从子协调器设置根视图控制器?
【发布时间】:2020-09-19 10:51:29
【问题描述】:

我正在尝试了解如何使用 XCoordinator 从子协调器设置根视图控制器。

我有一个运行应用协调器的应用委托。

我的模式是:

AppDelegate - 应用协调员 --- 主菜单协调器 --- 游戏协调员

(见图)

应用程序协调器不应该直接了解特定的视图控制器,因为我认为视图控制器应该由它们各自的协调器管理。

因此,应用协调器应管理协调器之间的流程并设置一个根初始协调器。

可悲的是,屏幕是空白的,并且一直抱怨我不能“不支持推送导航控制器”。

但是,如果我直接在我的 appcoordinator 中实例化视图控制器,那很好,我不知道为什么。

// AppCoordinator
enum AppRoute: Route {
    case mainmenu
    case game
}

class AppCoordinator: NavigationCoordinator<AppRoute> {

    init() {
        super.init(initialRoute: .mainmenu)
    }

    // MARK: Overrides
    override func prepareTransition(for route: AppRoute) -> NavigationTransition {
        let router = MainMenuCoordinator().strongRouter
        return .push(router)
    }
}

这应该会启动 MainMenuCoordinator 的初始视图控制器

enum MainMenuRoute: Route {
    case mainmenu
}

// MainMenuCoordinator
class MainMenuCoordinator: NavigationCoordinator<MainMenuRoute> {

    init() {
        super.init(initialRoute: .mainmenu)
    }


    override func prepareTransition(for route: MainMenuRoute) -> NavigationTransition {
        print ("route: \(route as Any)")

            let vc = MainMenuViewController.instantiate(.main)
            return .push(vc)
     }
}

但这会返回一个空白屏幕,并抱怨不支持推送。

但是,如果我移动这段代码:

let vc = MainMenuViewController.instantiate(.main)
return .push(vc)

到 AppCoordinator

像这样:

// MARK: AppCoordinator Overrides
override func prepareTransition(for route: AppRoute) -> NavigationTransition {
    let vc = MainMenuViewController.instantiate(.main)
    return .push(vc)
}

没关系。出现了一个屏幕——但主菜单协调器不再被“关注”

我想知道——你是如何做到的,以便应用程序协调器将责任委托给它的子协调器?

感谢您提供的任何帮助。 谢谢


// 编辑:根据提供的答案,我尝试了另一次尝试,将父协调器的引用传递给子协调器。

我希望mainmenucoordinator 使用它自己的路由集合;我不想仅仅依赖AppRoutes 中定义的任何路由。

所以我的应用协调员有这些路线:

enum AppRoute: Route {
    case mainmenu
    case game
}

class AppCoordinator: NavigationCoordinator<AppRoute> {

init() {
    let defaultRoute: AppRoute = .mainmenu
    super.init(initialRoute: defaultRoute)
    self.rootViewController.view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}

}

我的主要协调员有这些路线:

enum MainMenuRoute: Route {
    case mainmenu
    case selectPlayer
    case playgame
}

class MainMenuCoordinator: NavigationCoordinator<MainMenuRoute> {

    // For my child coordinators, keep a strong reference to parent
    private var router: StrongRouter<AppRoute>?
/// ...
}

当我开始初始化它时,我设置了父级。

// MainMenuCoordinator: Init
  convenience init(router: StrongRouter<AppRoute>) {
        self.init(initialRoute: .mainmenu)
    }

但现在它不会使用我为MainMenuCoordinator 定义的任何路由;相反,它使用AppRoute

例子:

尝试在MainMenuCoordinator.prepareTransition中设置路由器

override func prepareTransition(for route: MainMenuRoute) -> NavigationTransition {
        print ("route: \(route as Any)")

        switch route {
        case .mainmenu:
            let vc = MainMenuViewController.instantiate(.main)
            vc.router = strongRouter
            return .push(vc)
        // ....
      }
}

主菜单视图控制器持有对以下内容的引用:

class MainMenuViewController: UIViewController, Storyboarded {

    // MARK: - Stored properties
    var router: UnownedRouter<MainMenuRoute>!
}

通过这些编辑,根视图控制器现在是白色的;但记录器仍然抱怨我无法推送视图控制器。

【问题讨论】:

    标签: swift coordinator-pattern


    【解决方案1】:

    我正在这样做:

    class MainCoordinator: NavigationCoordinator<ApplicationRoute> {
    
        convenience init() {
            var defaultRoute: ApplicationRoute = .showAuthentification
            if ApplicationSettings.shared.isLoggedIn {
                defaultRoute = .showApplicationRoot
            }
    
            self.init(defaultRoute: defaultRoute)
            self.rootViewController.view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
        }
    
        override func prepareTransition(for route: ApplicationRoute) -> NavigationTransition {
            switch route {
                case .showAuthentification:
                    return .multiple(.dismissToRoot(animation: .fadeInstant),
                                     .presentFullScreen(AuthentificationCoordinator(router: strongRouter),
                                                        animation: .fadeInstant))
    
                case .showApplicationRoot:
                    return .multiple(.dismissToRoot(animation: .fadeInstant),
                                     .presentFullScreen(TabControllerCoordinator(router: strongRouter),
                                                        animation: .fadeInstant))
    
            }
        }
    }
    

    在独生子女协调员中:

    class AuthentificationCoordinator: NavigationCoordinator<AuthentificationRoute> {
        // For my child coordinators I keep a strong reference to the parent, so I can use it later
        private var router: StrongRouter<SMCApplicationRoute>?
    
        convenience init(router: StrongRouter<SMCApplicationRoute>) {
            self.init(defaultRoute: .initial)
            self.router = router
        }
    
        override func prepareTransition(for route: AuthentificationRoute) -> NavigationTransition {
            switch route {
            case .initial:
                let initialVC = LandingPageViewController.loadFromXIB(type: LandingPageViewController.self)
                initialVC.router = strongRouter
                return .push(initialVC, animation: .fade)
    
            case .showLogin:
                let loginVC = LoginViewController.loadFromXIB(type: LoginViewController.self)
                loginVC.router = strongRouter
                return .push(loginVC, animation: .fade)
    
            case .showHome:
                // Here I trigger the other route from MainCoordinator. If I log in, the AuthentificationCoordinator will get destroyed, with all the child coordinators with root controllers
                return .trigger(SMCApplicationRoute.showApplicationRoot, on: router!)
            }
        }
    }
    

    我认为有更好的解决方案,但我发现这是有效的。如果代码不能自我解释,请告诉我 ;)

    【讨论】:

    • 我没有授权层,但我想我可以试一试。我确实使用了 Paul Hudson 的高级协调器模式并得到了一个工作;虽然当协调员完成时我必须在其中一个子子项(叶子)中编写代码,并且是时候转移到另一个子项了。
    • 我喜欢他的方法,但是 XCoordinator 将这个想法提升到了一个新的水平。我选择了它,因为我在控制器之间使用了很多自定义转换,它很适合我。忽略 auth 层,关注协调器之间的连接。
    • strongRouter 在你的AuthentificationCoordinator 中指的是什么,没有引用它?是self.router吗?如果这个协调器有自己的路由怎么办?
    • 在我的主菜单协调器中,我希望它使用特定路由,这些路由作为对其控制下的任何 V/C 的引用传递。据我了解,在您的代码中,您在孩子中创建了一个父协调器引用;但这现在意味着我似乎无法初始化子协调器路线。如果我将private var router: StrongRouter&lt;AppRoute&gt;? 放在我的孩子协调员(mainmenucoordinator)中;然后我无法在 let vc = MainMenuViewController.instantiate(.main) 和任何 mainmenucoordinator 路由之间创建链接。
    • 我决定使用 P Hudson 在他的视频中建议的协调器,因为我的使用量非常小。结束票。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-09
    • 1970-01-01
    • 2016-01-27
    • 2020-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多