该方案曾被广泛使用,但在权衡利弊之后,我们现在更倾向于使用原生 Flow Controllers 或 Coordinators,详情请参考这里。
应该始终首选原生方案 (此处为双关语),并且我们认为减少依赖项是我们应该始终努力的目标。
因为传统的 App 导航会在 ViewControllers 之间引入紧耦合。 复杂的 App 导航看起来就像一个巨大的蜘蛛网。
除了 导航责任被分散到各个 ViewControllers 之外,修改一个 ViewController 可能会导致级联重新编译,从而导致编译速度变慢。
通过使用 Navigation enum
进行导航,我们可以解耦 ViewControllers 之间的关系。 也就是说,它们不再互相了解。 因此,修改 VCA
不会再触发 VCB
重新编译 \o/
// navigationController?.pushViewController(AboutViewController(), animated: true)
navigate(.about)
导航代码现在被封装在一个 AppNavigation
对象中。
enum MyNavigation: Navigation {
case about
case profile(Person)
}
Swift 枚举可以接受参数! 这对我们来说非常棒,因为这就是我们将在 ViewControllers 之间传递数据的方式 :)
struct MyAppNavigation: AppNavigation {
func viewcontrollerForNavigation(navigation: Navigation) -> UIViewController {
if let navigation = navigation as? MyNavigation {
switch navigation {
case .about:
return AboutViewController()
case .profile(let p):
return ProfileViewController(person: p)
}
}
return UIViewController()
}
func navigate(_ navigation: Navigation, from: UIViewController, to: UIViewController) {
from.navigationController?.pushViewController(to, animated: true)
}
}
一个很棒的事情是,如果某个导航案例没有被处理,swift 编译器会报错! 如果使用字符串 URLs,则不会出现这种情况 ;)
在 AppDelegate.swift
中,在所有事情之前
Router.default.setupAppNavigation(appNavigation: MyAppNavigation())
您现在可以从您的 View Controllers 中调用导航
navigate(MyNavigation.about)
使用您自己的枚举类型 (这里是 MyNavigation
) 来桥接 Navigation
,这样我们就不必输入我们自己的类型了。
extension UIViewController {
func navigate(_ navigation: MyNavigation) {
navigate(navigation as Navigation)
}
}
您现在可以这样写
navigate(.about)
解耦导航的另一个好处是,您现在也可以从 View Controllers 中提取跟踪代码。 只要发生导航,您就可以收到路由器的通知。
Router.default.didNavigate { navigation in
// Plug Analytics for instance
GoogleAnalitcs.trackPage(navigation)
}
Swift 3 编译器中存在一个严重的错误,即使文件没有更改,编译器也会重新构建文件。 这在以下位置有记录:https://forums.developer.apple.com/thread/62737?tstart=0
由于此错误,编译可能会这样进行
更改 ViewController1
-> Build
-> 编译 ViewController1
,它在 MyAppNavigation
中被引用,所以
MyAppNavigation
会被重新编译。 MyAppNavigation
在 AppDelegate
中被引用,这会重新编译,它又引用了 ... App
-> ViewController2
-> ViewController3
-> ViewControllerX
,您明白了吧。 在您意识到之前,整个 App 都会被重建 :/
一个好消息是,大多数的 App 耦合通常来自导航。 而 Router 可以解耦导航。
我们可以阻止这种无稽之谈,直到 Xcode 的未来版本修复此问题。 Router 可以通过在运行时注入我们的 AppNavigation 实现来帮助我们管理此问题。
在您的 AppDelegate.swift
中
// Inject your AppNavigation at runtime to avoid recompilation of AppDelegate :)
Router.default.setupAppNavigation(appNavigation: appNavigationFromString("YourAppName.MyAppNavigation"))
并确保您的 AppNavigation
实现现在是一个 class
,并且是 RuntimeInjectable
(运行时可注入的)
class MyAppNavigation: RuntimeInjectable, AppNavigation {
github "freshOS/Router"
只需将 Router.swift
文件复制并粘贴到您的 Xcode 项目中 :)
获取此存储库并在示例项目中构建 Framework 目标。 然后链接到该框架。
喜欢这个项目吗? 请喝咖啡或每月捐款支持我们,并帮助我们继续我们的活动 :)
成为赞助商,并将您的徽标放在我们在 Github 上的 README 中,并链接到您的网站 :)