UIViewController诞生的过程是什么(哪个方法遵循哪个方法)?

Ger*_*eri 57 iphone uiviewcontroller

有许多方法来替代,比如initWithNibname:,awakeFromNib,loadView,viewDidLoad,viewDidAppear:,layoutSubviews,我只是不能决定其中为了获得这些方法调用.

我只是"用心"覆盖其中一个.

任何详细的解释?

e.J*_*mes 173

Cocoa视图和viewController管理在幕后发生了很多事情.

1. viewController对象

最基本的是,viewController是一个通用的控制器对象.当它首次分配初始化时,它没有与之关联的视图对象.视图仅在需要时(以及如果)进行实例化.因此,在不考虑视图的情况下,viewController的生命周期与任何其他对象相同:

UIViewController * myVC = [[UIViewController alloc] initWith...];
...
[myVC release];
Run Code Online (Sandbox Code Playgroud)

viewControllers的指定初始化程序是-initWithNibname:bundle:.如果指定一个nib,viewController可以从该nib自动加载其视图并连接您定义的任何IBOutlet(有关更多详细信息,请参见下文).

2.加载和卸载视图

viewController将根据需要加载其视图.这种情况通常-view在第一次调用方法时发生,并且可能在程序中的任何时间发生,具体取决于您初始化UI的方式.在程序的生命周期中,视图也可能被破坏并重新加载,这取决于您管理UI的方式.当viewController识别出其视图是必需的但尚未加载时,-loadView将调用该方法.基本的消息流如下:

view
  loadView
  viewDidLoad
Run Code Online (Sandbox Code Playgroud)

请注意,如果你重写-view方法,-loadViewviewDidLoad不会被自动调用.如果覆盖-loadView,则必须设置viewController的view属性.否则,下一次调用-view将再次触发加载过程.

只需将view属性设置为,即可在程序生命周期内的任何时间卸载视图nil.-didReceiveMemoryWarning只要视图没有超级视图(即,它当前不是活动视图层次结构的一部分),默认实现将自动执行此操作.消息流程如下:

view = nil
   viewDidUnload
Run Code Online (Sandbox Code Playgroud)

2A.以编程方式加载视图

如果选择覆盖-loadView,则可以以任何方式创建视图,子视图,其他viewControllers以及这些对象之间的任何连接.当然,这意味着您还负责与您创建的对象相关的内存管理.如果您的子类重写-loadView,则应使用nilfor nibName和/ 来初始化它bundle.

2B.从笔尖加载视图

如果使用nib文件,默认实现-loadView将自动打开该nib文件,实例化其对象,添加它们之间的任何连接,并为您处理内存管理.

使用nib文件会让事情变得有点棘手,因为幕后发生了很多事情.为加载nib文件时实例化的每个对象-awakeFromNib调用该方法,并且无法保证nib文件中的其他对象在调用时已完全加载.

3.显示视图

-viewWillAppear:,-viewDidAppear:,-viewWillDisappear:-viewDidDisappear:正被显示时,视图或隐藏的屏幕上的,尤其是在动画transistions从一个视图向另一个仅调用.在程序的生命周期中,可以多次调用这些方法,因为视图在导航方案中交换进出.

4.查看布局

-layoutSubviews方法属于UIViewController.UIView当它们的边界被改变时,它被称为对象.如果UIView在程序中使用自定义子类,则此方法可用于执行自定义子视图布局,而不是依赖于Cocoa的默认自动调整方法.

把它们放在一起

由于复杂性,此过程有许多不同的方式,但正常的时间轴可能如下所示:

-[viewController initWithNibname:Bundle:]
-[viewController awakeFromNib]
-[viewController loadView]
-[view awakeFromNib]
-[viewController viewDidLoad]
-[viewController viewWillAppear]
-[viewController viewDidAppear]
...
-[viewController viewWillDisappear]  // user navigated away
-[viewController viewDidDisappear]
...
-[viewController viewWillAppear]     // user navigated back
-[viewController viewDidAppear]
...
-[viewController viewWillDisappear]  // user navigated away
-[viewController viewDidDisappear]
...
-[viewController setView:nil]        // memory warning, perhaps
-[viewController viewDidUnload]
...
-[viewController loadView]           // user navigated back
-[view awakeFromNib]
-[viewController viewDidLoad]
-[viewController viewWillAppear]
-[viewController viewDidAppear]
...
Run Code Online (Sandbox Code Playgroud)

  • 还值得注意的是,如果您从.xib文件加载视图控制器(即您的视图控制器在故事板中定义),则将调用initWithCoder而不是initWithNibName. (8认同)
  • 关于第4点,有可能(在iOS 5+中)覆盖` - (void)viewWillLayoutSubviews`和` - (void)viewDidLayoutSubviews`在`UIViewController`上,以便在生命周期的这一点插入逻辑. (2认同)

Jan*_*ski 37

我最近重新访问了这个并创建了一个测试项目:https://github.com/Janek2004/ViewControllerTest

在iOS模拟器上运行项目以查看UIViewController子类方法的执行顺序.每当我们使用Nib文件而不是故事板或以编程方式加载视图控制器时,顺序可能会有所不同.

  1. - [ViewController initWithCoder:] 从nib或storyboard中取消归档数据
  2. - [ViewController awakeFromNib]从Interface Builder存档或nib文件加载后,为接收器准备服务.
  3. - [ViewController loadView] 你永远不应该直接调用这个方法.视图控制器在请求其view属性但当前为nil时调用此方法.此方法加载或创建视图并将其分配给view属性.
  4. - [ViewController viewDidLoad] 在视图控制器将其视图层次结构加载到内存后调用此方法.
  5. - [ViewController viewWillAppear:]在接收者的视图即将添加到视图层次结构之前以及在配置任何动画以显示视图之前调用此方法.
  6. - [ViewController viewWillLayoutSubviews] 调用以通知视图控制器其视图即将布局其子视图.当视图的边界发生更改时,视图会调整其子视图的位置.您的视图控制器可以覆盖此方法以在视图布局其子视图之前进行更改.
  7. - [ViewController viewDidLayoutSubviews] 调用以通知视图控制器其视图刚刚布置了其子视图.当视图控制器视图的边界发生更改时,视图会调整其子视图的位置,然后系统会调用此方法.但是,调用此方法并不表示已调整视图子视图的各个布局.每个子视图负责调整自己的布局.
  8. - [ViewController viewDidAppear:]通知视图控制器其视图已添加到视图层次结构中.您可以覆盖此方法以执行与显示视图相关的其他任务.

  9. - [ViewController viewWillDisappear:]通知视图控制器其视图即将从视图层次结构中删除.调用此方法以响应从视图层次结构中删除的视图.在实际删除视图之前以及配置任何动画之前调用此方法.通知视图控制器其视图已添加到视图层次结构中.您可以覆盖此方法以执行与显示视图相关的其他任务.

  10. - [ViewController viewDidDisappear:] 通知视图控制器其视图已从视图层次结构中删除.


Har*_*ris 9

此过程中的另一个关键时刻是在任何子视图上调用layoutSubviews.正是在这一点,而不是更早,已经应用了故事板中配置的任何约束.如果您需要根据视图的约束坐标对视图的子视图进行任何调整,则必须在layoutSubviews中进行.如果你在viewDidLayoutSubviews中这样做,那就太早了,因为那些子视图还没有应用它们的约束(因为文档说"每个子视图负责调整它自己的布局".)如果你在viewDidAppear中这样做,显然太迟了,因为用户会看到你的子视图改变了坐标.因此,该过程中的另一个重要步骤是:

-viewController viewWillAppear
-viewController viewWillLayoutSubviews
-viewController viewDidLayoutSubviews
---> viewController.[any subview] layoutSubviews
-viewController viewDidAppear  
Run Code Online (Sandbox Code Playgroud)