iOS 7 - Difference between viewDidLoad and viewDidAppear
Asked Answered
A

7

47

Sorry but this may not be a programming question per se but more of an inquiry over the nature of iOS lifecycle functions.

I have an application where I have a function that creates four arrays and populates them via database queries. At first, I called the function from the viewDidLoad function, however, whenever the View is loaded, it takes time (around 3-4 seconds) before the view actually appears. So what I did was I created an activityViewIndicator and my viewDidLoad function looks something like:

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

}

However this doesn't work since the viewDidLoad function is triggered when the application is still in the previous View. The View only comes into display after viewDidLoad is already done. So what I did instead was move the array initialization to my viewDidAppear function which looks like:

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

}

However, when I deployed this, there was no delay whatsoever, making the activityIndicatorView useless.

My question is, why does it seem to me that there's a "performance difference" between viewDidLoad and viewDidAppear?

Airlie answered 6/3, 2014 at 4:19 Comment(4)
Does your method initializeArrays do the initialization in a separate thread? If it doesn't then you won't get the animation.Rebound
I don't think so. I didn't explicitly implement multi-threading.Airlie
Maybe lots of things were going on when you called viewDidLoad, and this leads to the delay. You can "lazy" load your VC with viewDidAppear. This would allow you to do whatever at a time when background tasks are not going on.Ehman
How are you quantifying a performance difference between viewDidLoad & viewDidAppear?Indicative
N
245

Please Follow the below View Controller Life Cycle Every Time. You will be amazed with the coding and performance of your application in this manner.

enter image description here

Numb answered 6/3, 2014 at 4:41 Comment(6)
Nice graphic - where did you get it? I may want to use this and I'd like to cite your source.Redden
i found it through google. It is really cool to work using this flow. Don't forget to upvote if you like this answer.Numb
btw, viewDidUnload has been deprecated in iOS6Wortman
The graphic is attributed to "Big Nerd Ranch iOS Programming" by https://mcmap.net/q/372001/-how-can-i-compare-viewdidload-to-viewdidappear-duplicate, so I assume it is from the book "iOS Programming: The Big Nerd Ranch Guide". The discussion at #5563438 points out the diagram is a bit outdated especially w.r.t. the viewDidUnload part of the cycle (as Yas T. also points out here I see).Pleura
Just as an added note (and, at least, important to me) is that viewDidLayoutSubviews is missing between viewWillAppear: and viewDidAppear:. At the point viewDidLayoutSubviews is called, the sizes (frames/bounds and stuff) is already calculated, while in viewWillAppear: they're not.Radiosonde
So that means if the View is dissmissed and is again presented than the viewDidLoad will be called?Danica
R
4

I'm going to point you to Apple's docs because I think there is a need for some more explanation of the View Controller lifecycle than just answering your question as phrased.

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

Ultimately, your view controller has a life cycle:

init - however you initialize your view controller

viewWillLoad/viewDidLoad - called when the view is constructed (via the first call to retrieve the view controller's UIView via it's view property - aka lazy loading)

viewWillAppear: - when the view is being prepared to appear either immediately (animated == NO) or view a transition (animated == YES)

viewDidAppear: - if the view appearance wasn't cancelled and the view controller's view fully appears

viewWillDisappear: - complements viewWillAppear:

viewDidDisappear: - complements viewDidAppear:

viewWillUnload/viewDidUnload - deprecated APIs when the view is unload due to memory constraints (don't worry about these anymore)

dealloc - the view controller itself is being deallocated

In the end though, I believe your issue may be that you are blocking the main thread with your array initialization. You should read up on asynchronous programming but in the meantime you could do something like this:

- (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];
    } 
}
Redden answered 6/3, 2014 at 4:49 Comment(0)
K
2

There is absolutely no performance difference between viewDidLoad: and viewDidAppear:. Both are normal functions running on the main thread. If your initializeArrays method takes 3 seconds to load, it will take 3 seconds in whichever method you call it. Since you are not explicitly changing threads, any function in which you call initializeArrays will not exit until it's finished.

The call to [self.activityIndicatorView startAnimating] will basically "mark" the activityIndicatorView so that another UI function on the main thread will start it animating. (This is why the main or 'UI' thread is important, because all animations and visual updates to the screen are coordinated on it). So the function that will actually get the activityIndicator going doesn't get called until initializeArrays is finished and you have called "stopAnimating" already.

Try this:

- (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];
}
Knotgrass answered 6/3, 2014 at 4:58 Comment(0)
N
1

However, when you are loading things from a server(or heavy data processing), you also have to think about latency. If you pack all of your network communication into viewDidLoad or viewWillAppear, they will be executed before the user gets to see the view - possibly resulting a short freeze of your app. It may be good idea to first show the user an unpopulated view with an activity indicator of some sort. When you are done with your networking, which may take a second or two (or may even fail - who knows?), you can populate the view with your data. Good examples on how this could be done can be seen in various twitter clients. For example, when you view the author detail page in Twitterrific, the view only says "Loading..." until the network queries have completed.

ViewDidLoad calls only once when you initialized your ViewController but Viewdidapper calls every time.

Noll answered 6/3, 2014 at 4:28 Comment(4)
viewDidLoad is not called once based on your view controller initializationRedden
the same thing i said above , in tabbarcontroller when you initialized and add VCs in tabbar then they calls viewdidload but when you tap the tabs in tabbar viewdidload not calls.Noll
@Redden can you explain a bit in which view controller initialization you every time calls the viewDidLoadNoll
See my answer for more detailRedden
R
1

The activityIndicatorViews will only animate if the main thread (the UI thread) is not busy. viewDidLoad: and viewDidAppear: are both executed on the main thread. If, as you mention, the initializeArrays method does not execute in a separate thread, then the activityIndicatorViews will never have time to animate.

Rebound answered 6/3, 2014 at 4:42 Comment(0)
U
1

View Did Load - First method , which is called when view is loaded first time but not appeared on screen/window, only loaded.

only called one time when view is loaded first time.

View Did Appear - After viewWillAppear called , viewDidAppear will be called. It means view is appeared on screen now.

Called number of times as user is moving from that viewcontroller to another view controller and coming back .

**

  • View Life Cycle

**

1)ViewDidLoad (called only when view is loaded first time), then 2)ViewWillAppear (will be called number of times), then 3)ViewDidAppear (will be called number of times), then 4)ViewWillDisAppear (will be called number of times), then 5)ViewDidDisAppear (will be called number of times)

Uta answered 22/1, 2016 at 7:56 Comment(0)
E
0

For those coding programmatically (without Interface Builder), loadView is the first available lifecycle method, not viewDidLoad, and programmatic development often makes more use of loadView than viewDidLoad, so keep that in mind. A part of what IB does is write the loadView for you. IB is just a way to shorten programmatic development but if you want to best understand Cocoa Touch, you should understand it programmatically.

loadView comes first and is where UI elements are typically created, including the view of the view controller itself (which programmatic development must explicitly create). Constraints can be added here but they are not handled until later in the lifecycle.

viewDidLoad is where "logic" is typically made once the UI elements have been established.

viewWillAppear and viewWillLayoutSubviews are called next right before the UI itself is to construct itself.

viewDidLayoutSubviews is called next and can be called multiple times on the same view controller before it actually appears. This is where auto layout is applied. This is also where the programmer can get a view's safe area values since they are not available before this method.

viewDidAppear comes last after the view controller's view has appeared in a view hierarchy.

Excitor answered 29/8, 2018 at 16:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.