iOS

iOS 子控制器

2022-09-30  本文已影响0人  anny_4243

UIViewController有一个childViewControllers数组属性,存储其管理的子控制器,一般用在当前控制器需要用作容器,并将显示内容分配到其他控制器来实现的场景,而这些“其他控制器”既然要在容器控制器中显示,就要被容器控制器所引用,通过childViewController的方式。

实际上我们经常会与容器控制器打交道,包括最常用的UINavigationController、UITabBarController以及前几年很流行的侧边栏的结构,其实现都是在当前控制器管理子控制器,对子控制器的view进行调度和展示。有意思的是,虽然我们经常使用UINavigationController和UITabBarController,在获取其管理的子控制器时,并不是通过childViewControllers,而是直接通过另一个类似的属性viewControllers来获取,虽然打印其结果显示其存储的内容都是一样的,但childViewControllers是容器本身对子控制器进行管理的根据,其增减都是不需要开发者知晓和维护的,如果开发者想了解,就通过viewControllers接口来获取。

或许读者很少用到甚至见过使用childViewController来进行开发的场景,但实际上,却有很多场景是适合用childViewController来做的,并且有很明显的优势。举个简单的使用场景,如果你的手机中有各大电商的应用,打开订单列表,可以发现大多数的订单列表如图所示。

子控制使用示例

在同一个页面中,有多种状态,每种状态都是一个列表,而这些列表都是相似的,这就是childViewController的使用场景中的一种。接下来介绍具体用法。

创建一个新工程,基于UINavigatController,之所以基于UINavigationController第一是因为导航栏比较常见,二是由于需要放置一个UISegmentControl来触发切换childViewController。接着需要创建两个UIViewController的子类作为ViewController的childViewController,为FirstViewController和SecondViewController,两者为了区分,在其中部加一个Label,title为控制器的名称,这里便不展示这两个控制器的实现代码了。

我们看一下ViewController。ViewController是创建工程系统自动生成的,我们在Storyboard中将其嵌套在UINavigationController中。ViewController的代码如下。

在代码中可以看到,我们在创建FirstViewController和SecondViewController实例后,分别将其设置为当前控制器的子控制器,之后则调用firstVC和secondVC的didMoveToParentViewController:方法表示已经添加到容器控制器中了。并且之后将firstVC.view添加在当前控制器的view上,这样默认第一个view则显示出来了。每当我们单击UISegmentControl进行切换时,会将之前的子控制器view先removeFromSuperView,再把要展示的子控制器view添加到容器控制器的view上,如此便实现了childViewController的功能,效果如图所示。

效果已经实现了,并且实现的过程也比较简单,但其中有些内容还需要再说明一下。在上面的代码中,我们使用了一个方法:

     - (void)didMoveToParentViewController:(nullable UIViewController *)parent

寻找到该方法的定义可以看到,这是在UIViewController.h中自iOS 5就有的方法,同时还有一个方法:

     - (void)willMoveToParentViewController:(nullable UIViewController *)parent

这两个方法是系统自带的,用于在childViewController的场景下使用,但需要有注意的地方。实际上,这两个方法需要容器控制器在childViewController切换时由childViewController去调用,它们都有一个相同的参数,即childViewController的容器视图控制器。既然是由childViewController去调用,那么你可能以为,在容器控制器addChildViewController之前调用[childVC willMoveToParentViewController:self],之后调用[childVCdidMoveToParentViewController:self]就可以,移除的时候同理,只是参数为nil。实际上并非如此,由于父视图控制器与子视图控制器的关系略显复杂,我们在将子视图控制器添加到父视图控制器上的操作时,并不需要先调用willMoveToParentViewController:,这个调用已经在父视图控制器调用addChildViewController:方法内部帮助开发者完成了,但系统不会知道你什么时候已经真正添加到父视图控制器上,可能这其中还会有个过渡效果。相反的是,当子控制器需要从父视图控制器上移除,则需要手动调用[childVCwillMoveToParentViewController:nil],而[childVC removeFromParentViewController]则会帮我们自动调用[childVCdidMoveToParentViewController:nil]方法。虽然在我们的示例代码中,并没有涉及去remove子视图控制器,但如果情况比较复杂时,可以考虑暂时释放某些不常用的子视图控制器,等需要的时候再加载进来。

介绍完了childViewController的使用方法和注意点。再从开发角度上来考虑使用childViewController的优点:①业务代码分散,更清晰,例如开头提到的电商订单列表的页面,如果全部放在一个页面去做,复杂度过大,整个代码会显得杂乱,而在子页面则方便每一种类进行自我管理。②懒加载,页面真正需要出现时才会加载到内存中,性能更优。③使用方便,仅仅一个添加子控制器的操作以及增减显示的view方法,远比多个UITableView要好用得多。

摘自《iOS开发快速进阶与实战》

上一篇下一篇

猜你喜欢

热点阅读