iOS 7 - viewDidLoad和viewDidAppear之间的区别

时间:2014-03-06 04:19:17

标签: ios objective-c

很抱歉,这可能不是一个编程问题,而是更多关于iOS生命周期功能性质的询问。

我有一个应用程序,我有一个函数创建四个数组并通过数据库查询填充它们。起初,我从viewDidLoad函数调用了函数,但是,每当加载View时,在视图实际出现之前需要花费时间(大约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之间存在“性能差异”?

7 个答案:

答案 0 :(得分:224)

请每次按照以下查看控制器生命周期。您将以这种方式对应用程序的编码和性能感到惊讶。

enter image description here

答案 1 :(得分:4)

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

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

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

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

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

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

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];
    } 
}

答案 2 :(得分:2)

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

对[self.activityIndi​​catorView startAnimating]的调用将基本上“标记”activityIndi​​catorView,以便主线程上的另一个UI函数将启动它的动画。 (这就是主要或'UI'线程很重要的原因,因为屏幕上的所有动画和视觉更新都是相互协调的)。因此,实际获取activityIndi​​cator的函数不会被调用,直到initializeArrays结束并且你已经调用了“stopAnimating”。

试试这个:

- (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];
}

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

查看已加载 - 第一个方法,在第一次加载视图时调用,但未在屏幕/窗口中显示,仅加载。

第一次加载视图时只调用一次。

查看显示 - 调用viewWillAppear后,将调用viewDidAppear。这意味着视图现在出现在屏幕上。

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

**

  • 查看生命周期

**

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

答案 6 :(得分:0)

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

loadView首先出现,通常是在其中创建UI元素的地方,包括视图控制器本身的视图(必须明确创建程序开发)。可以在这里添加约束,但是直到生命周期的后期才能处理。

loadView通常是在建立UI元素后进行“逻辑”处理。

viewDidLoadviewWillAppear在UI自身构造之前就被调用。

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

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