【问题标题】:iOS 7 - Difference between viewDidLoad and viewDidAppeariOS 7 - viewDidLoad 和 viewDidAppear 之间的区别
【发布时间】:2014-04-08 12:28:27
【问题描述】:

抱歉,这本身可能不是一个编程问题,而更多的是对 iOS 生命周期函数性质的询问。

我有一个应用程序,其中我有一个创建四个数组并通过数据库查询填充它们的函数。起初,我从viewDidLoad 函数中调用了该函数,但是,每当加载视图时,视图实际出现之前都需要一些时间(大约 3-4 秒)。所以我所做的是我创建了一个activityViewIndicator,而我的viewDidLoad 函数看起来像:

- (void)viewDidLoad:(BOOL)animated{
    [super viewDidLoad];

    NSLog(@"viewDidLoad Entered");
    [self.activityIndicatorView startAnimating];

    partInput.delegate = self;
    brandInput.delegate = self;
    barcodeInput.delegate = self;
    itemNameInput.delegate = self;

    //initializeArrays is the function that initializes the arrays
    [self initializeArrays];

    [self.activityIndicatorView stopAnimating];

}

但是这不起作用,因为当应用程序仍在前一个视图中时会触发viewDidLoad 函数。视图仅在viewDidLoad 完成后才会显示。所以我所做的就是将数组初始化移动到我的 viewDidAppear 函数,它看起来像:

- (void)viewDidAppear:(BOOL)animated{
    NSLog(@"viewDidAppear loaded successfully");
    [self.activityIndicatorView startAnimating];

    partInput.delegate = self;
    brandInput.delegate = self;
    barcodeInput.delegate = self;
    itemNameInput.delegate = self;

    [self initializeArrays];

    [self.activityIndicatorView stopAnimating];

}

但是,当我部署它时,没有任何延迟,使 activityIndi​​catorView 无用。

我的问题是,为什么在我看来 viewDidLoadviewDidAppear 之间存在“性能差异”?

【问题讨论】:

  • 您的方法initializeArrays 是否在单独的线程中进行初始化?如果没有,那么您将无法获得动画。
  • 我不这么认为。我没有明确地实现多线程。
  • 当您致电viewDidLoad 时,可能发生了很多事情,这会导致延迟。你可以用viewDidAppear“懒惰地”加载你的VC。这将允许您在后台任务不进行时做任何事情。
  • 您如何量化 viewDidLoad 和 viewDidAppear 之间的性能差异?

标签: ios objective-c


【解决方案1】:

但是,当您从服务器加载内容(或繁重的数据处理)时,您还必须考虑延迟问题。如果您将所有网络通信打包到 viewDidLoadviewWillAppear 中,它们将在用户看到视图之前执行 - 可能会导致短暂的冻结你的应用程序的强>。首先向用户显示带有某种活动指示器的未填充视图可能是个好主意。当您完成网络时,可能需要一两秒钟(甚至可能失败 - 谁知道?),您可以使用您的数据填充视图。在各种 Twitter 客户端中可以看到如何做到这一点的好例子。例如,当您在 Twitterrific 中查看作者详细信息页面时,该视图只会显示“正在加载...”,直到网络查询完成。

ViewDidLoad 在初始化 ViewController 时只调用一次,但 Viewdidapper 每次都会调用。

【讨论】:

  • viewDidLoad 不会根据您的视图控制器初始化调用一次
  • @NSProgrammer 你能解释一下你每次调用viewDidLoad时哪个视图控制器初始化
  • 查看我的回答了解更多详情
【解决方案2】:

请每次都遵循以下视图控制器生命周期。您会惊讶于以这种方式编写的应用程序的编码和性能。

【讨论】:

  • 漂亮的图形 - 你从哪里得到的?我可能想用这个,我想引用你的来源。
  • 我是通过谷歌找到的。使用这个流程工作真的很酷。如果您喜欢这个答案,请不要忘记投票。
  • 顺便说一句,viewDidUnload 在 iOS6 中已被弃用
  • 该图由stackoverflow.com/a/15247449/179583 归于“Big Nerd Ranch iOS Programming”,所以我假设它来自“iOS Programming: The Big Nerd Ranch Guide”一书。 stackoverflow.com/questions/5562938/… 的讨论指出该图有点过时,尤其是 w.r.t。 viewDidUnload 循环的一部分(正如我看到的 Yas T. 在这里指出的那样)。
  • 就像一个附加说明(至少对我来说很重要)一样,viewDidLayoutSubviewsviewWillAppear:viewDidAppear: 之间缺失。在调用viewDidLayoutSubviews 时,已经计算了尺寸(帧/边界和内容),而在viewWillAppear: 中则没有。
【解决方案3】:

activityIndicatorViews 仅在主线程(UI 线程)不忙时才会进行动画处理。 viewDidLoad:viewDidAppear: 都在主线程上执行。如果,正如您所提到的,initializeArrays 方法不在单独的线程中执行,那么activityIndicatorViews 将永远没有时间进行动画处理。

【讨论】:

    【解决方案4】:

    我将向您指出 Apple 的文档,因为我认为需要对 View Controller 生命周期进行更多解释,而不仅仅是按照措辞回答您的问题。

    https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html

    最终,您的视图控制器有一个生命周期:

    init - 但是你初始化你的视图控制器

    viewWillLoad/viewDidLoad - 在构造视图时调用(通过第一次调用以通过视图属性检索视图控制器的 UIView - 也称为延迟加载)

    viewWillAppear:- 当视图准备立即出现(动画 == NO)或查看过渡(动画 == YES)时

    viewDidAppear: - 如果视图外观没有被取消并且视图控制器的视图完全出现

    viewWillDisappear:- 补充 viewWillAppear:

    viewDidDisappear: - 补充 viewDidAppear:

    viewWillUnload/viewDidUnload - 由于内存限制而卸载视图时不推荐使用的 API(不再担心这些)

    dealloc - 视图控制器本身正在被释放

    最后,我相信您的问题可能是您的数组初始化阻塞了主线程。您应该阅读异步编程,但同时您可以执行以下操作:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        // other stuff
    
        __weak typeof(self) weakSelf = self;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            typeof(weakSelf) strongSelf = weakSelf;
            if (strongSelf) {
                [strongSelf initializeArraysSynchronously];
                dispatch_async(dispatch_get_main_queue(), ^{
                    strongSelf.doneIntializingArrays = YES;
                    [strongSelf.activityIndicatorView stopAnimating];
                });
            }
        });
    }
    
    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        if (!self.doneInitializingArrays) {
            [self.activityIndicatorView startAnimating];
        } 
    }
    

    【讨论】:

      【解决方案5】:

      viewDidLoad: 和 viewDidAppear: 之间绝对没有性能差异。两者都是在主线程上运行的普通函数。如果您的 initializeArrays 方法需要 3 秒来加载,那么无论您调用哪个方法都需要 3 秒。由于您没有显式更改线程,因此您调用 initializeArrays 的任何函数在完成之前都不会退出。

      对 [self.activityIndi​​catorView startAnimating] 的调用基本上会“标记”activityIndi​​catorView,以便主线程上的另一个 UI 函数将启动它的动画。 (这就是主线程或“UI”线程很重要的原因,因为屏幕上的所有动画和视觉更新都在其上进行协调)。因此,在 initializeArrays 完成并且您已经调用“stopAnimating”之前,不会调用实际让 activityIndi​​cator 运行的函数。

      试试这个:

      - (void)viewDidLoad:(BOOL)animated{
          [super viewDidLoad];
      
          NSLog(@"viewDidLoad Entered");
          [self.activityIndicatorView startAnimating];
      
          partInput.delegate = self;
          brandInput.delegate = self;
          barcodeInput.delegate = self;
          itemNameInput.delegate = self;
      }
      
      - (void)viewDidAppear:(BOOL)animated{
          //initializeArrays is the function that initializes the arrays
          [self initializeArrays];
          [self.activityIndicatorView stopAnimating];
      }
      

      【讨论】:

        【解决方案6】:

        View Did Load - First 方法,当视图第一次加载但未出现在屏幕/窗口上时调用,仅加载。

        仅在第一次加载视图时调用一次。

        View Did Appear - 调用 viewWillAppear 后,将调用 viewDidAppear。这意味着视图现在出现在屏幕上。

        当用户从该视图控制器移动到另一个视图控制器并返回时调用的次数。

        **

        • 查看生命周期

        **

        1)ViewDidLoad(仅在第一次加载视图时调用),然后 2)ViewWillAppear(将被调用次数),然后 3)ViewDidAppear(将被调用次数),然后 4)ViewWillDisAppear(将被调用次数),然后 5)ViewDidDisAppear(会被调用的次数)

        【讨论】:

          【解决方案7】:

          对于那些以编程方式(没有 Interface Builder)进行编码的人,loadView 是第一个可用的生命周期方法,而不是 viewDidLoad,并且编程开发通常更多地使用 loadView 而不是 viewDidLoad,所以请记住这一点。 IB 所做的部分工作是为您编写loadView。 IB 只是缩短程序化开发的一种方式,但如果您想最好地理解 Cocoa Touch,您应该以编程方式理解它。

          loadView 最先出现,通常是在其中创建 UI 元素,包括视图控制器本身的视图(程序开发必须显式创建)。可以在此处添加约束,但直到生命周期的后期才会处理它们。

          viewDidLoad 是 UI 元素建立后通常进行“逻辑”的地方。

          viewWillAppearviewWillLayoutSubviews 在 UI 本身构建自身之前被调用。

          viewDidLayoutSubviews 是接下来调用的,并且可以在同一个视图控制器上被多次调用,然后才实际出现。这是应用自动布局的地方。这也是程序员可以获取视图的安全区域值的地方,因为在此方法之前它们不可用。

          viewDidAppear 出现在视图控制器的视图出现在视图层次结构中之后。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-18
            • 1970-01-01
            相关资源
            最近更新 更多