首页 文章

希望了解iOS UIViewController的生命周期

提问于
浏览
241

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

特别是,我想知道如何在Mono Touch中使用 InitializeViewDidLoadViewWillAppearViewDidAppearViewWillDisappearViewDidDisappearViewDidUnloadDispose 方法作为 UIViewController 类 .

12 回答

  • 28

    截至iOS 6及以后版本 . 新图如下:

    enter image description here

  • 15
    init(coder:)
    

    在Storyboard中创建应用程序的视图时, init(coder:) 是被调用以实例化视图控制器并使其生效的方法 . 此方法的 Contract 实际上是在NSCoding协议中定义的,因此您不会在 UIViewController 文档中看到它 .

    调用此方法时,您的视图很可能会在不久的将来(或非常近的将来)显示,但此时无法保证它实际显示 . 所以这可能是开始整理好东西的好时机,但这里不要太多,否则你会浪费处理能力 . 在此方法中,您可以实例化依赖项,包括以编程方式添加到视图中的子视图 . 请注意, init(coder:) 在对象的生命周期中仅被调用一次,因为所有init方法都是 .

    viewDidLoad()
    

    当视图加载到内存中时,在 init(coder:) 之后调用此方法,在视图控制器对象的生命周期中也只调用此方法一次 . 这是在Storyboard中进行任何视图初始化或设置的好地方 . 也许您想以编程方式添加子视图或自动布局约束 - 如果是这样,这是一个很好的地方来做其中任何一个 . 请注意,仅仅因为视图已加载到内存中并不一定意味着它将很快显示 - 为此,您需要查看 viewWillAppear . 哦,记得在你的实现中调用 super.viewDidLoad() 以确保你的超类的viewDidLoad有机会完成它的工作 - 我通常在实现开始时调用super .

    viewWillAppear(_:)
    

    始终在 viewDidLoad 之后调用(出于显而易见的原因,如果您考虑它),并且在屏幕上显示给用户的视图之前,将调用 viewWillAppear . 这使您有机会进行任何最后一分钟的视图设置,启动网络请求(当然是在另一个类中),或刷新屏幕 . 与 viewDidLoad 不同, viewWillAppear 在第一次显示视图时以及再次显示视图时调用,因此可以在视图控制器对象的生命周期内多次调用它 . 当用户点击后退按钮,关闭模式对话框,在选项卡栏控制器中选择视图控制器选项卡或其他各种原因导致视图即将出现时,会调用它 . 确保在实现中的某个时刻调用 super.viewWillAppear() - 我通常首先做的事情 .

    viewWillDisappear(_:)
    

    viewWillAppear 类似,此方法在视图从屏幕上消失之前调用 . 和 viewWillAppear 一样,在视图控制器对象的生命周期内可以多次调用此方法 . 当用户离开屏幕时调用它 - 可能是关闭屏幕,选择另一个选项卡,点击显示模态视图的按钮,或者在导航层次结构中向下导航 . 这是隐藏键盘,保存状态以及可能取消运行计时器或网络请求的好地方 . 与视图控制器生命周期中的其他方法一样,请务必在 viewWillDisappear 中的某个位置调用 super .

  • 360

    解释官方文件中的州过渡:https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/index.html

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

    Valid State Transitions

  • 9

    按照Apple docs

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

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

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

    viewWillDisappear - 在视图控制器的内容视图从应用程序的视图层次结构中删除之前调用 . 使用此方法执行清除任务,例如提交更改或重新签署第一响应者状态 .

    viewDidDisappear - 在视图控制器的内容视图已从应用程序的视图层次结构中删除后调用 . 使用此方法执行其他拆卸活动 .

  • 18

    iOS 10,11 (Swift 3.1,Swift 4.0)

    根据 UIViewControllerUIKit 开发人员中,

    1. loadView()

    这是子类在不使用nib时应创建自定义视图层次结构的位置 . 永远不应该直接打电话 .

    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(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)

    在视图转换时调用 .

    11. willMove(toParentViewController parent: UIViewController?)

    12. didMove(toParentViewController parent: UIViewController?)

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

    从子父中删除子项时,这两种方法中的父参数都是nil;否则它等于新的父视图控制器 .

    13. didReceiveMemoryWarning()

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

  • 383

    让我们专注于负责UIViewController's生命周期的方法:

    • 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's lifecycle diagram

    有关更多信息,请查看UIViewController Class Reference .

  • 109

    这适用于最新的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

    此事件创建控制器管理的视图 . 仅在以编程方式创建视图控制器时调用它 . 这使它成为在代码中创建视图的好地方 .

    This is where subclasses should create their custom view hierarchy if they aren't using a nib. 
    Should never be called directly.
    

    2. loadViewIfNeeded

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

    Loads the view controller's view if it has not already been set.
    

    3. viewDidLoad

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

    Called after the view has been loaded. For view controllers created in code, this is after -loadView.
    For view controllers unarchived from a nib, this is after the view is set.
    

    4. viewWillAppear

    只要视图出现在屏幕上,此事件就会通知 viewController . 在此步骤中,视图具有已定义的边界,但未设置方向 .

    Called when the view is about to made visible. Default does nothing.
    

    5. viewWillLayoutSubviews

    这是生命周期中最终确定边界的第一步 . 如果您没有使用约束或自动布局,则可能需要在此处更新子视图 . 这仅适用于iOS> = 5.0 . 因此,如果你支持iOS <5.0,那么不要指望它出现在图片中 .

    Called just before the view controller's view's layoutSubviews method is invoked.
    Subclasses can implement as necessary. The default is a nop.
    

    6. viewDidLayoutSubviews

    此事件通知视图控制器已设置子视图 . 它是设置后对子视图进行任何更改的好地方 . 这仅适用于iOS> = 5.0 . 因此,如果你支持iOS <5.0,那么不要指望它出现在图片中 .

    Called just after the view controller's view's layoutSubviews method is invoked.
    Subclasses can implement as necessary. The default is a nop.
    

    7. viewDidAppear

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

    Called when the view has been fully transitioned onto the screen.
    Default does nothing
    

    8. viewWillDisappear

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

    Called when the view is dismissed, covered or otherwise hidden.
    

    9. viewDidDisappear

    这是生命周期的最后一步,任何人都可以解决,因为此事件在呈现 viewController 的视图消失,解除,覆盖或隐藏之后才会触发 .

    Called after the view was dismissed, covered or otherwise hidden. 
    Default does nothing
    

    现在根据 Apple ,当您实现此方法时,您应该记得调用该特定方法的 super 实现 .

    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.
    

    希望这有帮助 . 谢谢 .

    UPDATE - 正如@ThomasW指向内部注释 viewWillLayoutSubviewsviewDidLayoutSubviews 也将在加载主视图的子视图时被调用,例如当加载表视图或集合视图的单元格时 .

  • 16

    iOS会在适当的时间自动调用所有这些命令加载/显示/隐藏视图控制器时 . 重要的是要注意这些方法附加到 UIViewController 而不是 UIView 本身 . 只使用 UIView ,您将无法获得任何这些功能 .

    有's great documentation on Apple'的网站here . 简单地说:

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

    • ViewWillAppear - 在视图出现之前调用,适合隐藏/显示字段或每次在视图可见之前发生的任何操作 . 因为您可能在视图之间来回切换,所以每次您的视图即将出现在屏幕上时都会调用此视图 .

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

    • ViewWillDisappear / DidDisappear - 与 ViewWillAppear / ViewDidAppear 相同的想法 .

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

  • 0

    UIViewController生命周期如下图所示:

    http://rdkw.wordpress.com/2013/02/24/ios-uiviewcontroller-lifecycle/

    A view controller's lifecycle, diagrammed

  • 6

    方法中没有提到方法 viewWillLayoutSubviewsviewDidLayoutSubviews ,但这些方法在 viewWillAppearviewDidAppear 之间调用 . 它们可以被多次调用 .

  • 35

    Haider的答案对于iOS 6之前是正确的 . 但是,从iOS 6开始,viewDidUnload和viewWillUnload永远不会被调用 . docs州:"Views are no longer purged under low-memory conditions and so this method is never called."

  • 16

    这里有很多过时和不完整的信息 . 仅适用于 iOS 6 and newer

    • loadView [a]

    • viewDidLoad [a]

    • viewWillAppear

    • viewWillLayoutSubviews 是第一次完成边界

    • viewDidLayoutSubviews

    • viewDidAppear

    • * viewWillLayoutSubviews [b]

    • * viewDidLayoutSubviews [b]


    脚注:

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

    (b)可再称为0次或更多次 .

相关问题