UIViewController(I)

需求与分析介绍

  在日常的开发中常有这样一种需求,通过切换标签来切换不同的页面,如果在一个 controller 管理这些 view 的话,代码就显得耦合度过高,也与 Apple 的 MVC 模式不符合,Apple 推荐一个 controller 管理一个 view。
  这样就有人建议类似 [self.view addSubview:viewController.view] 的方式用另一个 controller 来控制。
  但是这样会产生一个新的问题:直接 add 进去的subView不在 viewController的 view hierarchy 内,事件不会正常传递,如:旋转、触摸等,属于危险操作违背CocoaTouch开发的设计MVC原则,viewController应该且只应该管理一个view hierarchy。
  同时我们也要考虑另一个问题:这些子 view 大多数不会一直处于界面上,只是在某些情况下才会出现,例如登陆失败的提示 view,上传附件成功的提示 view,网络失败的提示 view 等。但是虽然这些 view 很少出现,但是我们却常常一直把它们放在内存中。另外,当收到内存警告时,我们如何把这些 view 从 super view 中去掉?

为了解决以上的问题,在iOS5 苹果给出一些方法以及属性用来解决这些问题:

@property(nonatomic,readonly) NSArray<__kindof UIViewController *> *childViewControllers;

//添加ViewController,建立父子ViewController关系
//调用该方法时,会自动调用willMoveToParentViewController: 方法,但是不会自动调用didMoveToParentViewController: 方法,要显示调用
- (void)addChildViewController:(UIViewController *)childController;


//通知childController,即将解除父子关系,设置 childController的parentController即将为nil
- (void)willMoveToParentViewController:(nullable UIViewController *)parent;


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


//在移除childController前不会调用willMoveToParentViewController: ,所以需要显示调用这个方法
- (void)removeFromParentViewController;


- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;


Demo

添加ViewController

ViewController.m 文件中

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
    
    [self.view addSubview:self.clickBtn];
}

- (void) clickAction:(UIButton *)sender {
    NewController *nc = [NewController new];
    
    [self addChildViewController:nc];
    //[nc willMoveToParentViewController:self];
    //将nc的view加到父类的view上去,当然还要确定子view在父类view上的frame,否则不显示
    [self.view addSubview:nc.view];
    //以通知childController,完成了父子关系的建立
    [nc didMoveToParentViewController:self];
}

效果:


未点击Button前

点击Button后


移除ViewController

NewController.m

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.clickBtn];
}

- (void) clickAction:(UIButton *)sender {
    
    //在移除childController前不会调用willMoveToParentViewController: ,所以需要显示调用这个方法
    [self willMoveToParentViewController:nil];
    
    //将childController的view从父类的view中移除
    [self.view removeFromSuperview];
    //解除父子ViewControllet的关系
    [self removeFromParentViewController];
    
}

效果图:


NewController 移除前

NewController 移除后


addSubView: 和 addChildController: 先后调用顺序区别

  当childViewController没有被加到任何父视图控制器时,如果把childViewController的view加到别的视图上,viewWillAppear和viewDidAppear会正常调用。但是当childViewController被加到一个父视图控制器上后,要注意区别:
①先调用addSubView,再调用addChildViewController
  若先调用addSubView,viewWillAppear和viewDidAppear会各调用一次;,再调用addChildViewController时,与父视图控制器的事件同步,即当父视图控制器的viewDidAppear调用时,childViewController的viewDidAppear方法会再调用一次。所以viewDidAppear方法被调用了两次

②先调用addChildViewController,再调用addSubView
  先调用addChildViewController,childViewController的事件与父视图控制器同步,当父视图控制器的viewDidAppear调用时,childViewController的viewDidAppear方法会调用一次,再调用addSubView也不会触发viewWillAppear和viewDidAppear。






参考资料:
addChildViewController 等方法详解

iOS addChildViewController详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容