来理解iOS UIViewController的生命周期

你能解释一下管理UIViewController生命周期的正确方式吗?

特别地,我想知道如何使用InitializeViewDidLoadViewWillAppearViewDidAppearViewWillDisappearViewDidDisappearViewDidUnloadDispose方法在Mono触摸的UIViewController类。

263052 次浏览

当你加载/显示/隐藏视图控制器时,iOS会在适当的时间自动调用所有这些命令。需要注意的是,这些方法被附加到UIViewController而不是__abc1本身。仅仅使用UIView是得不到这些特性的。

苹果网站在这里上有很棒的文档。简单地说:

  • ViewDidLoad -创建类并从xib加载时调用。非常适合初始设置和一次性工作。

  • ViewWillAppear -在视图出现之前调用,用于隐藏/显示字段或任何你想在视图可见之前发生的操作。因为您可能在视图之间来回切换,所以每当您的视图即将出现在屏幕上时,都会调用这个函数。

  • ViewDidAppear -在视图出现后调用-开始动画或从API加载外部数据的好地方。

  • ViewWillDisappear/DidDisappear -与ViewWillAppear/ViewDidAppear相同。

  • ViewDidUnload/ViewDidDispose -在Objective-C中,这是你清理和释放东西的地方,但这是自动处理的,所以你真的不需要在这里做太多。

更新:ViewDidUnload在iOS 6中已弃用,因此更新了相应的答案。

UIViewController的生命周期如图所示:

A view controller's lifecycle, diagram

使用Xamarin Native/Mono Touch的优势在于,它使用了原生api,因此它遵循与Apple文档中相同的ViewController生命周期。

海德尔的答案适用于ios 6之前的版本。然而,在iOS 6中,viewDidUnload和viewWillUnload从未被调用。文档状态:“视图在低内存条件下不再被清除,因此此方法永远不会被调用。”

在官方文档中解释状态转换:https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/index.html

这张图片显示了各种视图' will '和' did '回调方法之间的有效状态转换

有效的状态转换:

< p > . < br > 取自:https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Art/UIViewController类Reference_2x.png

方法viewWillLayoutSubviewsviewDidLayoutSubviews在图中没有提到,但是它们在viewWillAppearviewDidAppear之间被调用。它们可以被多次调用。

iOS 6及以后版本。新的图表如下:

enter image description here

这里有很多过时和不完整的信息。仅适用于iOS 6及更新版本:

  1. loadView(一)
  2. viewDidLoad(一)
  3. viewWillAppear
  4. viewWillLayoutSubviews是第一次确定边界
  5. viewDidLayoutSubviews
  6. viewDidAppear
  7. * viewWillLayoutSubviews[b]
  8. * viewDidLayoutSubviews[b]

< p > <子> 脚注: < / sub > < / p > < p > <子> (a) -如果你在didReceiveMemoryWarning期间手动空出视图,loadViewviewDidLoad将再次被调用。也就是说,默认情况下,每个视图控制器实例只能调用loadViewviewDidLoad一次。 < / sub > < / p > < p > <子> (b)可以被称为额外的0或更多次。 < / sub > < / p >

这是针对最新的iOS版本(用Xcode 9.3, Swift 4.1修改)。下面是使UIViewController的生命周期完整的所有阶段。

  • loadView()

  • loadViewIfNeeded()

  • viewDidLoad()

  • viewWillAppear(_ animated: Bool)

  • viewWillLayoutSubviews()

  • viewDidLayoutSubviews()

  • viewDidAppear(_ animated: Bool)

  • viewWillDisappear(_ animated: Bool)

  • viewDidDisappear(_ animated: Bool)

我来解释一下这些阶段。

1. loadView

该事件创建/加载控制器管理的视图。它可以从关联的nib文件或空UIView加载(如果找到null)。 这使得它成为以编程方式在代码中创建视图的好地方。< / p >

如果子类没有使用nib,它们应该在这里创建自定义视图层次结构。 不要直接打电话。 只有在以编程方式创建视图并将根视图分配给view属性时才重写此方法 重写时不要调用超级方法 未经 < / p >

2. loadViewIfNeeded

如果当前viewController的视图尚未设置,则此方法将加载视图,但请记住,这仅在iOS >=9.0中可用。因此,如果你支持iOS <9.0,那么不要指望它会进入画面。

如果视图控制器的视图尚未被设置,则加载视图控制器的视图。

3.viewDidLoad

viewDidLoad事件仅在视图创建并加载到内存时调用,但视图的边界尚未定义。这是初始化视图控制器将要使用的对象的好地方。

视图加载后调用。对于在代码中创建的视图控制器,它位于-loadView之后。 对于从nib中未归档的视图控制器,这是在视图被设置之后

4. viewWillAppear

当视图出现在屏幕上时,此事件通知viewController。在这一步中,视图有定义的边界,但没有设置方向。

当视图即将变为可见时调用。违约不起任何作用。

5. viewWillLayoutSubviews

这是生命周期中的第一步,边界在这里被最终确定。如果你没有使用约束或自动布局,你可能想要更新这里的子视图。这只适用于iOS >=5.0。因此,如果你支持iOS <5.0,那么就不要指望它会出现在画面中。

在视图控制器的视图的layoutSubviews方法被调用之前调用。 子类可以根据需要实现。默认为nop

6. viewDidLayoutSubviews

这个事件通知视图控制器子视图已经被设置。在设置了子视图之后,可以在这里对它们进行任何更改。这只适用于iOS >=5.0。因此,如果你支持iOS <5.0,那么就不要指望它会出现在画面中。

在视图控制器的视图的layoutSubviews方法被调用之后调用。 子类可以根据需要实现。默认为nop

7. viewDidAppear

viewDidAppear事件在视图显示在屏幕上之后触发。这使得它成为从后端服务或数据库获取数据的好地方。

当视图完全转换到屏幕上时调用。 默认不执行任何操作

8. viewWillDisappear

当所呈现的viewController的视图即将消失、解散、覆盖或隐藏在其他viewController后面时,viewWillDisappear事件触发。这是一个可以限制网络调用、使计时器失效或释放绑定到viewController的对象的好地方。

当视图被解散、覆盖或以其他方式隐藏时调用。

9. viewDidDisappear

这是生命周期的最后一步,任何人都可以在呈现的viewController视图消失、解散、覆盖或隐藏之后触发此事件。

在视图被解散,覆盖或以其他方式隐藏后调用。 默认不执行任何操作

现在,根据苹果,当你实现这个方法时,你应该记得调用那个特定方法的super实现。

如果你子类化UIViewController,你必须调用这个方法的超实现,即使你没有使用NIB。(为了方便起见,默认的init方法将为您执行此操作,并为该方法的两个参数指定nil。)在指定的NIB中,File的Owner代理应该将其类设置为视图控制器子类,视图出口连接到主视图。如果你用nil的nib名称调用这个方法,那么这个类的-loadView方法将尝试加载一个名称与你的视图控制器的类相同的nib。如果实际上不存在这样的NIB,则必须在调用-view之前调用-setView:,或者覆盖-loadView方法以编程方式设置视图。

希望这有帮助。 谢谢。< / p >

更新 -正如@ThomasW在评论中指出的那样,当加载主视图的子视图时,viewWillLayoutSubviewsviewDidLayoutSubviews也会在其他时候被调用,例如当加载表视图或集合视图的单元格时。

更新 -正如@Maria在注释中指出的那样,loadView的描述被更新了

让我们集中在负责的ui生命周期的方法上:

  • < p > 创造:

    - (void)init

    - (void)initWithNibName: < / p >

  • < p > 视图创建:

    - (BOOL)isViewLoaded

    - (void)loadView

    - (void)viewDidLoad

    - (UIView *)initWithFrame:(CGRect)frame

    - (UIView *)initWithCoder:(NSCoder *)coder < / p >

  • < p > 视图状态改变的处理:

    - (void)viewDidLoad

    - (void)viewWillAppear:(BOOL)animated

    - (void)viewDidAppear:(BOOL)animated

    - (void)viewWillDisappear:(BOOL)animated

    - (void)viewDidDisappear:(BOOL)animated

    - (void)viewDidUnload < / p >

  • < p > 内存警告处理:

    - (void)didReceiveMemoryWarning < / p >

  • < p > 存储单元分配

    - (void)viewDidUnload

    - (void)dealloc < / p >

UIViewController's lifecycle diagram

有关更多信息,请查看UIViewController类引用

iOS 10、11 (Swift 3.1,Swift 4.0)

根据UIKit开发者中的UIViewController

1. loadView ()

如果子类没有使用笔尖,它们应该在这里创建自定义视图层次结构。不要直接打电话。

2. loadViewIfNeeded ()

如果视图控制器的视图尚未被设置,则加载视图控制器的视图。

3.viewDidLoad ()

在视图加载后调用。对于在代码中创建的视图控制器,它位于-loadView之后。对于从nib未归档的视图控制器,这是在视图被设置之后。

4. viewWillAppear(_ animated: Bool)

当视图即将变为可见时调用。违约不起任何作用

5. viewWillLayoutSubviews ()

在视图控制器的视图的layoutSubviews方法被调用之前调用。子类可以根据需要实现。违约不起任何作用。

6. viewDidLayoutSubviews ()

在视图控制器的视图的layoutSubviews方法被调用之后调用。子类可以根据需要实现。违约不起任何作用。

7. viewDidAppear(_ animated: Bool)

当视图完全转换到屏幕上时调用。违约不起任何作用

8. viewWillDisappear(_ animated: Bool)

当视图被解散、覆盖或以其他方式隐藏时调用。违约不起任何作用

9. viewDidDisappear(_ animated: Bool)

在视图被解散,覆盖或以其他方式隐藏后调用。违约不起任何作用

10. viewWillTransition(大小:CGSize,协调器:UIViewControllerTransitionCoordinator)

视图正在转换时调用。

11. willMove(到父视图控制器:UIViewController?)

12. didMove(to arentviewcontroller parent: UIViewController?)

这两个方法是公共的,供容器子类在子控制器之间转换时调用。如果它们被覆盖,覆盖应确保调用超级。

当子对象从父对象中移除时,这两个方法中的父对象参数都为nil;否则它等于新的父视图控制器。

13. didReceiveMemoryWarning ()

当父应用程序接收到内存警告时调用。在iOS 6.0上,默认情况下它将不再清除视图。

As per 苹果的文档-开始开发iOS应用程序(Swift) -使用视图控制器-理解视图控制器生命周期

__abc0 -当视图控制器的内容视图(其视图层次结构的顶部)被创建并从故事板加载时调用。 ... 使用此方法执行视图控制器所需的任何额外设置

__abc0 -在视图控制器的内容视图添加到应用程序的视图层次结构之前调用。使用此方法可以触发在内容视图显示在屏幕上之前需要发生的任何操作

__abc0 -在视图控制器的内容视图被添加到应用程序的视图层次结构之后调用。使用此方法可以触发任何需要在屏幕上显示视图时立即发生的操作,例如获取数据或显示动画。

__abc0 -在视图控制器的内容视图从应用的视图层次结构中移除之前调用。使用此方法执行清理任务,如提交更改或放弃第一响应器状态。

__abc0 -在视图控制器的内容视图从应用程序的视图层次结构中移除后调用。使用此方法可执行额外的拆卸活动。