无侵入控制NavigationBar显示和隐藏和Coordinator

2021-10-27 00-27-03.2021-10-27 00_27_36.gif

要实现这种显示、隐藏 NavigationBar 的效果,只需要在要隐藏的 Controller 里加入以下代码

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: true)
    }

在要显示 NavigationBar 的 Controller 里加入以下代码

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: true)
    }

试想一下,在 mainController 需要隐藏导航栏,那么就需要在 mainController 的每个要 push 去的 controller 都需要加入以上代码。
这就比如一个公司里,有 java、iOS、Android、测试、产品、设计等不同工种的员工,而团队的管理者(整个进程)不知道谁做 java、谁做测试、谁做设计,需要协调时去当面问一下:你是什么职位

解决这个问题的方案有两种:
1、Coordinator
用一个或者多个专门的Coordinator去负责所有的跳转逻辑
我们在写代码时经常有以下代码:

navigationController?.pushViewController(AViewController.init(), animated: true)
navigationController?.popViewController(animated: true)

这里省略掉了"self.navigationController"。问题在于,NavigationController 是持有当前控制器的,这里的 self.navigationController,就像是你在叫你的领导帮你做事,这里的领导对你的需求一无所知。比如工位卫生需要打扫,你告诉领导让他找人打扫,再比每天都会有网络故障,出故障后你告诉领导让他找人维护
这显然是不合理的
Coordinator 就是把 push、pop 等 navigationController 应该做的事情,集合起来处理的一种设计模式
Coordinator 负责从 AController push 到 BController,从 BController push 到 CCtonroller,再 pop回来这些事情
push 时 AController 传参给 Coordinator,Coordinator 再创建 BController 并把参数给 BController,BController 的回调交给 Coordinator,Coordinator 去处理回调而不是 AController 直接处理
好处是解决了领导不认识员工的问题,不足是仍然要在每个控制器写上 viewWillAppear 和 setNavigationBarHidden 的代码

2、Hook
运用 runtime 调换 controller 的 viewWillAppear 方法,统一处理
这里先讲思路再说优缺点
1、在 app 启动时交换 controller 的 viewWillAppear 方法
2、新建一个 plist 写入要显示和要隐藏的控制器名称,value 为 bool 控制显示或者隐藏
3、交换方法后,就可以判断是否为 plist 设置好的 controller,判断是否执行 显示、隐藏操作
demo:
https://github.com/haoburongyi/AOPManager
优点:
无侵入、不用每个 controller 都写一遍 viewWillAppear 和 setNavigationBarHidden 方法,精简控制器代码。修改时只需要修改 plist 文件即可
缺点:
没有文档或者没有告知下一个开发者,不便于维护
不足:
无法到达 Coordinator 的统一 push、pop 操作

最后谈一谈为什么我放弃了 Coordinator
我们进行 push、pop操作时,必须要拿到 controller 才能拿到 navigationController,在 iOS 的子控件 view 中,可以通过循环遍历 superview 拿到 controller,也可以通过代码架构方式拿到(要确定代码架构),(比如通过 keyWindow 可以拿到 rootViewController,rootViewController 是 TabbarController,通过 Child 可 selectedIndex 可以拿到当前的 navigationController)进行 push
试想一下,app 内有内购功能,所以 vip 这个 button 就在各个地方都会出现,点击后没开通 vip 的用户跳转至开通页面
这里最好的设计模式就是 self manager,就是自己去管理自己,而不是把跳转逻辑交给上层 controller 了,button 上层嵌套自定义 view,自定义 view 嵌套 在 tableViewCell 内,tableViewCell 上层是 tableView,最后才是控制器,一个 button 往上写回调已经是地狱了,每个都这么写的就绝望了。不如一句

// self 是view,为了清晰说明这里 “self.” 不省略,controller 为扩展的找控制器属性
self.controller?.navigationController?.pushxxxxxxx
或者
self.navigationController?.pushxxxxxxx

如果在这种时候继续使用 Coordinator,就会陷入这种地狱,解决方法也有,就是在 view 内往上一层一层遍历找到 Coordinator,或者用单例的 Coordinator。但是当 主页、新闻、我的三个在 tabbarController 上的根 navigationController 用三个不同的 Coordinator 管理时,找到 Coordinator 也无法确定调用哪个方法,并且直接违反了使用 Coordinator 的初衷--统一管理
以上为个人对 navigaitonController 的一些理解,如有纰漏、错误或者更好的想法,请指点

你可能感兴趣的:(无侵入控制NavigationBar显示和隐藏和Coordinator)