【问题标题】:What is the difference between -viewWillAppear: and -viewDidAppear:?-viewWillAppear: 和 -viewDidAppear: 有什么区别?
【发布时间】:2011-08-03 14:11:58
【问题描述】:

-[UIViewController viewWillAppear:]-[UIViewController viewDidAppear:] 有什么区别?

【问题讨论】:

  • 感谢 BoltClock,但如果可能的话,请给我两个例子..
  • @BoltClock 如果这是真的,那就太好了。我猜有 15 位投赞成票的人读了方法名称,但从未实际测量过……从 Google 来到这里,因为这不是他们之间的区别
  • 特别是:parentView.viewDidAppear 在 Apple 实际显示 parentView 之前被调用 A LONG TIME ... Apple 首先(原子地)绘制所有子视图 ...如果您有很多子视图或复杂的子视图,那么“viewDidAppear”可以过早地调用数十或数百毫秒:(。

标签: iphone ios


【解决方案1】:

一般来说,我是这样做的:

  1. ViewDidLoad - 每当我向应与视图一起显示的视图添加控件时,我立即将其放入 ViewDidLoad 方法中。基本上,只要将视图加载到内存中,就会调用此方法。因此,例如,如果我的视图是具有 3 个标签的表单,我将在此处添加标签;没有这些表单,视图永远不会存在。

  2. ViewWillAppear:我使用ViewWillAppear 通常只是为了更新表单上的数据。因此,对于上面的示例,我将使用它来实际将域中的数据加载到表单中。创建UIViews 相当昂贵,您应该尽可能避免在ViewWillAppear 方法上这样做,因为当它被调用时,这意味着iPhone 已经准备好向用户显示UIView,并且您在此处执行的任何繁重操作都会以非常明显的方式影响性能(例如动画延迟等)。

  3. ViewDidAppear:最后,我使用 ViewDidAppear 启动新线程来处理需要很长时间才能执行的事情,例如进行 Web 服务调用以获取额外数据上面的表格。好消息是,由于视图已经存在并且正在向用户显示,因此您可以在获取数据时向用户显示一个很好的“等待”消息。

【讨论】:

  • 抱歉,viewWillAppear 中的“将我的域中的数据加载到表单中”是什么意思?你的意思是通过网络下载?但是你也建议在viewDidAppear下载东西?
  • @Philip007 我认为 Stack 指的是这种类型的域:en.wikipedia.org/wiki/Domain-specific_modeling。数据是从您的模型或类似模型中加载的。
  • 这个答案应该在文档中。这对澄清三种方法之间的区别非常有帮助。谢谢!
  • +1 我对理解这三者之间的区别有点困惑,但你刚刚把它清理得更完美了@ChetanBhalara
  • @ChetanBhalara 但如果你在ViewDidAppear 上投入大量时间,你很容易让用户对 UI 感到困惑 :)
【解决方案2】:

viewDidLoad ===>>> 把你的初始化代码放在这里。不要放置在视图生命周期中可能发生变化的动态数据。因此,如果您从核心数据中提取数据,如果这可能会在视图的生命周期内发生变化,那么您不想在此处执行此操作。例如:假设您有一个选项卡控制器。您从 tab1 切换到 tab2 并在 tab2 中更改模型上的某些内容。如果您返回 tab1 并且您的模型代码在 viewDidLoad 中完成,则不会更新(假设您没有使用 KVO 或 NSFetchedResultsController 等)。

viewWillAppear ===>>> 每次视图即将出现时都会调用它,无论视图是否已经在内存中。把你的动态代码放在这里,比如模型逻辑。

viewDidAppear ===>>> 将仅当您确定视图在屏幕上时才想做的昂贵操作(例如网络调用)放在这里。

注意:如果您的应用程序在后台运行并返回到前台,您需要使用 NSNotificationCenter 来处理此问题。我在下面的 cmets 中为此编写了代码。您可能认为 viewWillAppear/viewDidAppear 会触发。在那里设置一个断点并测试它。它不火。因此,如果您的应用在后台发生了某些变化,您需要使用通知进行更新。

【讨论】:

  • 每次取消最小化应用程序时是否都会运行 ViewWill 或 ViewDid?
  • @Jeef 这是一个很好的问题。除非应用程序在后台被系统或用户杀死,否则两者都不会运行。当应用程序未最小化时,您必须做的是您必须使用 NSNotificationCenter 和 addObserver 作为名称 UIApplicationWillEnterForegroundNotification。选择器应该是 applicationWillEnterForeground:它有一个 NSNotification 参数。将您的代码放入该方法中以重新加载数据等。您可以做的是创建一个重新加载方法,您可以从该方法调用该方法,如果它们需要相同,还可以使用 viewDidAppear。
  • @Jeef 类似这样: - (void)viewDidLoad { [[NSNotificationCenter defaultCenter] addObserver:self 选择器:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; } - (void) applicationWillEnterForeground: (NSNotification *)notif {// 在这里回复任何内容}
【解决方案3】:

在加载实际视图之前调用viewWillAppear 方法。

viewDidAppear 方法在视图已经加载并且您想要显示某些内容时被调用。

【讨论】:

    【解决方案4】:

    viewWillAppear:
    ■ 在视图添加到窗口的视图层次结构之前调用
    ■ 在 [vc.view layoutSubviews] 之前调用(如有必要)
    viewDidAppear:
    ■ 在视图添加到视图层次结构后调用
    ■ 在 [vc.view layoutSubviews] 之后调用(如果需要)

    【讨论】:

      【解决方案5】:

      一些观察:

      • 第一次实例化视图时调用viewDidLoad 方法。 IBOutlet 引用在调用它时已连接,但不是在此之前。不过,视图的frame 可能在调用它时尚未建立。这是添加/配置子视图及其相关约束的好地方。但是,如果您要根据主视图的尺寸手动配置 frame 值,那么这些框架的配置应该推迟到 viewWillAppearviewDidLayoutSubviews

      • 当视图层次结构中的视图即将开始呈现时调用viewWillAppear 方法。值得注意的是,这在视图呈现的动画(如果有)开始时被调用。它的伙伴viewWillDisappear 显然在从该视图开始转换时被调用。

      • 当视图的呈现完成时调用viewDidAppear 方法,特别是当任何和所有相关动画完成时。它的伙伴viewDidDisappear 显然在从该视图转换完成时被调用。

      两个重要的警告:

      • viewDidLoad 在第一次实例化视图时被调用一次且仅一次。另一方面,viewWillAppearviewDidAppear 不仅会在第一次呈现视图时被调用,而且在随后每次重新呈现相同的视图时都会被调用。例如,当您第一次呈现视图时,将调用所有这三个方法。如果相关视图随后呈现另一个视图,该视图随后被关闭,则在将相关视图添加并动画回视图层次结构时通常会再次调用 viewWillAppearviewDidAppear,但 viewDidLoad 不会。 viewDidLoad 仅在首次创建此特定实例时调用。

        因此,如果您想在每次视图重新出现时执行某项操作(例如,您关闭或弹出该视图),请在 viewWillAppearviewDidAppear 中执行此操作。如果您希望它仅在第一次实例化视图时发生,请在 viewDidLoad 中执行此操作。

      • viewWillAppear 的调用并不能保证到该视图的转换将永远完成。值得注意的是,如果您使用由实时用户输入驱动的交互式过渡,则可以取消该交互式过渡。即,仅仅因为viewWillAppear 被调用,并不意味着viewDidAppear 会被调用。通常是这样,但如果取消交互手势,则不会(因为过渡从未完成)。

        在 WWDC 2013 上,在交互式过渡的背景下,一位演示者开玩笑说他们应该将 viewWillAppear 重命名为“viewMightAppear,或viewWillProbablyAppear,或iReallyWishThisViewWouldAppear”。

        内置交互手势的一个示例是使用UINavigationController 并且您“从左边缘滑动”以启动视图的弹出。 viewWillAppear 将为您弹出的视图调用,但如果您取消“从左边缘滑动”以返回到您开始此弹出手势的视图,则弹出被取消并且 viewDidAppear因为您开始弹回的视图将永远不会被调用。

        这样做的最终结果是您应该小心,不要编写假定每次调用viewWillAppear 最终都会调用viewDidAppear 的代码。如果转换被取消,则不会出现这种情况。

      【讨论】:

        【解决方案6】:

        viewwillappear 将在加载视图之前调用,以便您可以在加载该视图之前执行某些任务,并且 viewdidappear 将在加载视图后调用,以便在该方法中完成发布任务

        【讨论】:

          【解决方案7】:

          “will”和“did”之间的区别...顾名思义,viewWillAppear 在视图即将出现之前被调用,而 viewDidAppear 在视图出现时被调用。

          【讨论】:

          • 看看接受的答案兄弟,其中包含 70 多个赞成票。 :)
          【解决方案8】:

          1) ViewWillAppear:视图实际加载到内存中,在视图控制器中调用一次并有它的框架,但仍然没有向用户显示

          2) ViewDidAppear:控制器添加到视图层次结构中,因此您可以呈现给下一个控制器, 此外,视图确实布局了子视图

          【讨论】:

            【解决方案9】:

            前者发生在视图出现之前,后者发生在之后。

            【讨论】:

              【解决方案10】:

              总结一下:

              -viewWillAppear -> 更新数据(从表格视图重新加载数据)

              -viewDidAppear -> 昂贵的操作(API 调用带有一个很好的进度界面!)

              【讨论】:

                【解决方案11】:

                顾名思义,viewWillAppear 在视图即将出现之前被调用,viewDidAppear 在视图出现时被调用。

                【讨论】:

                  【解决方案12】:

                  用例,即我应该什么时候使用哪个?

                  viewDidLoad - 当标签、按钮(即任何控件/子视图)连接到 View 的界面文件时,如果你想与 ViewController 的 View 同时加载所有这些,并且如果你想加载这一次进入内存并完成

                  viewWillAppear - 比如说,您想在每次 viewController 出现在屏幕上时更改视图的背景颜色。或者更现实的是,如果您想要在一天中的夜间使用 DarkMode 背景颜色,并在白天使用浅色背景视图,请在 viewWillAppear 中获取此代码

                  这里的另一个很好的用例 https://stackoverflow.com/a/39395865/5438240

                  还要注意,如果您使用的是导航堆栈(UINavigationController),即将弹出的 viewController 将调用 viewWillDisappear(),而接下来将位于堆栈顶部的 ViewController 将具有 @ 987654327@打来电话

                  【讨论】:

                    【解决方案13】:

                    一般来说,我是这样做的:

                    1. ViewDidLoad - 每当我向应与视图一起显示的视图添加控件时,我立即将其放入 ViewDidLoad 方法中。基本上,只要将视图加载到内存中,就会调用此方法。因此,例如,如果我的视图是具有 3 个标签的表单,我将在此处添加标签;没有这些表单,视图将永远存在。

                    2. ViewWillAppear:我使用 ViewWillAppear 通常只是为了更新表单上的数据。因此,对于上面的示例,我将使用它来实际将域中的数据加载到表单中。 UIViews 的创建是相当昂贵的,你应该尽可能避免在 ViewWillAppear 方法上这样做,因为当它被调用时,这意味着 iPhone 已经准备好向用户显示 UIView,你在这里做的任何事情将以非常明显的方式影响性能(例如动画延迟等)。

                    3. ViewDidAppear:最后,我使用 ViewDidAppear 来启动新线程来处理需要很长时间才能执行的事情,例如进行 Web 服务调用以获取上述表单的额外数据。好处是因为视图已经存在并且正在向用户显示,您可以在获取数据时向用户显示一条漂亮的“等待”消息。

                    【讨论】:

                      【解决方案14】:

                      viewDidLoad - 当特定的视图控制器类加载到内存中时调用此函数。使用此方法,您可以对从 storyboard/nib 文件加载的视图执行额外的初始化。

                      ViewWillAppear - 通知并执行与显示视图相关的自定义任务。

                      ViewDidApper - 执行与呈现视图相关的其他任务。如果你重写了这个方法,你必须在你的实现中调用 super。

                      【讨论】:

                        猜你喜欢
                        • 2012-10-11
                        • 2014-04-12
                        • 2012-08-26
                        • 1970-01-01
                        • 2012-12-11
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-05-19
                        相关资源
                        最近更新 更多