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

特别地,我想知道如何使用初始化,ViewDidLoad, ViewWillAppear, ViewDidAppear, ViewWillDisappear, ViewDidDisappear, ViewDidUnload和Dispose方法在UIViewController类的Mono Touch。


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

苹果网站上有很好的文档。简单地说:

ViewDidLoad - Called when you create the class and load from xib. Great for initial setup and one-time-only work. ViewWillAppear - Called right before your view appears, good for hiding/showing fields or any operations that you want to happen every time before the view is visible. Because you might be going back and forth between views, this will be called every time your view is about to appear on the screen. ViewDidAppear - Called after the view appears - great place to start an animations or the loading of external data from an API. ViewWillDisappear/DidDisappear - Same idea as ViewWillAppear/ViewDidAppear. ViewDidUnload/ViewDidDispose - In Objective-C, this is where you do your clean-up and release of stuff, but this is handled automatically so not much you really need to do here.


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

UIViewController的生命周期如图所示:

使用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 '回调方法之间的有效状态转换

有效的状态转换:

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


图中没有提到viewWillLayoutSubviews和viewDidLayoutSubviews方法,但是在viewWillAppear和viewDidAppear之间调用这些方法。它们可以被多次调用。


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


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

(一)未经 viewDidLoad[一] 那些有点 viewWillLayoutSubviews是边界第一次被最终确定 viewDidLayoutSubviews 在viewDidAppear * viewWillLayoutSubviews [b] * viewDidLayoutSubviews [b]


脚注:

(a) -如果在didReceiveMemoryWarning期间手动空出视图,loadView和viewDidLoad将再次被调用。也就是说,默认情况下,loadView和viewDidLoad每个视图控制器实例只被调用一次。

(b)可称为额外0次或更多次。


这是最新的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. 未经

此事件创建/加载控制器管理的视图。它可以从一个相关的nib文件或一个空的UIView加载,如果发现null。 这使得它成为以编程方式在代码中创建视图的好地方。

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

2. loadViewIfNeeded

如果当前viewController的视图还没有设置,那么这个方法将加载视图,但记住,这只在iOS >=9.0中可用。所以如果你支持iOS <9.0,那就别指望它会出现。

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

3.viewDidLoad

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

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

4. 那些有点

当视图出现在屏幕上时,此事件通知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

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

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

9. viewDidDisappear

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

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

按照苹果的规定,当你实现这个方法时你应该记得调用那个特定方法的super implementation。

If you subclass UIViewController, you must call the super implementation of this method, even if you aren't using a NIB. (As a convenience, the default init method will do this for you, and specify nil for both of this methods arguments.) In the specified NIB, the File's Owner proxy should have its class set to your view controller subclass, with the view outlet connected to the main view. If you invoke this method with a nil nib name, then this class' -loadView method will attempt to load a NIB whose name is the same as your view controller's class. If no such NIB in fact exists then you must either call -setView: before -view is invoked, or override the -loadView method to set up your views programatically.

希望这对你有所帮助。 谢谢。

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

更新- @Maria在评论中指出,loadView的描述被更新


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

Creation: - (void)init - (void)initWithNibName: View creation: - (BOOL)isViewLoaded - (void)loadView - (void)viewDidLoad - (UIView *)initWithFrame:(CGRect)frame - (UIView *)initWithCoder:(NSCoder *)coder Handling of view state changing: - (void)viewDidLoad - (void)viewWillAppear:(BOOL)animated - (void)viewDidAppear:(BOOL)animated - (void)viewWillDisappear:(BOOL)animated - (void)viewDidDisappear:(BOOL)animated - (void)viewDidUnload Memory warning handling: - (void)didReceiveMemoryWarning Deallocation - (void)viewDidUnload - (void)dealloc

更多信息请查看UIViewController类参考。


iOS 10,11 (Swift 3.1,Swift 4.0)

根据UIKit开发者的UIViewController,

1. loadView ()

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

2. loadViewIfNeeded ()

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

3. 视图加载()

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

4. viewWillAppear(_ animated: Bool)

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

5. viewWillLayoutSubviews ()

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

6. 视图布局子视图()

在视图控制器的视图的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上,默认情况下它将不再清除视图。


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

viewDidLoad()—Called when the view controller’s content view (the top of its view hierarchy) is created and loaded from a storyboard. … Use this method to perform any additional setup required by your view controller. viewWillAppear()—Called just before the view controller’s content view is added to the app’s view hierarchy. Use this method to trigger any operations that need to occur before the content view is presented onscreen viewDidAppear()—Called just after the view controller’s content view has been added to the app’s view hierarchy. Use this method to trigger any operations that need to occur as soon as the view is presented onscreen, such as fetching data or showing an animation. viewWillDisappear()—Called just before the view controller’s content view is removed from the app’s view hierarchy. Use this method to perform cleanup tasks like committing changes or resigning the first responder status. viewDidDisappear()—Called just after the view controller’s content view has been removed from the app’s view hierarchy. Use this method to perform additional teardown activities.