Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

viewdidAppear: why do I have to call super?

From Apple's documents, I have to call super at some point if I override the method. I have two ViewControllers connected together with a segue. If you press a button in the first VC, you go to the second VC. The problem is when I overrode viewDidAppear of the first VC, and called super, viewDidAppear of the second VC was called, which was not what I wanted. I deleted super and everything was fine.

  • Why is calling super.viewDidAppear from the first VC would call secondVC.viewDidAppear?
  • Is not calling viewDidAppear a bad idea?

Thank you in advance!

like image 890
Maximus S Avatar asked Dec 19 '22 07:12

Maximus S


1 Answers

Not calling [super viewDidAppear] is indeed a bad idea. The base class for UIViewController has code in viewDidAppear that needs to be called or things won't work correctly. I've forgotten to call [super viewDidAppear] before, and things don't work correctly. I forget what the bad effects are, but they are subtle and confusing to debug.

It does not make sense that the second view controller's call to [super viewDidAppear] is calling the first view controller. I think you are misunderstanding.

My guess is that your second view controller is a subclass of the first view controller. In your second view controller, when you call [super viewDidAppear], it calls the parent class' implementation of the method. Since your second view controller's class is the same as the first view controller, that parent CLASS's method gets called. It is not being called on the first view controller instance however. The child view controller has multiple versions of viewDidAppear that it can call: The custom method in it's .m file, the method that's written in it's parent class's .m file, and any implementations of the method that are defined in it's grandparent class, great-grandparent class, etc.

Metaphor:

Imagine the evolution of dogs. First there are only dogs, no breeds of dogs. Dogs can wag their tails, so all dogs have a "wag" method.

A mother dog has a puppy that is the first pointer. (Class Pointer.) It inherits all the methods of it's parent class, including wag, but also has a method "point".

It also does a little wiggle at the end of it's normal wag, so it has a custom implementation of the wag method. It's a new ending on the standard wag method, so the Pointer class first invokes the wag method of the parent class, then it's custom method.

In the implementation of the pointer's "wag" method, it calls [super wag] to do the parent CLASS's wag before adding it's own wiggle at the end.

So the Pointer class's wag method might look like this:

@implementation Pointer

- (void) wag;
{ 
  [super wag];
  [self tailWiggle];
}

@end

Now, if you have the mother (an instance of class Dog) and the puppy (an instance of class Pointer) standing next to each other, and you have breakpoints on both of their wag methods, here's what will happen.

When the puppy wags it's tail, it first invokes the parent **CLASS's* wag method. (It doesn't ask it's mother, a Dog, to wag it's tail, it uses the dog wag method defined by the parent class.)

Since you have a breakpoint in the wag method of both the Dog class and the Pointer class, you'll see a breakpoint in the Dog class's wag method. However, it is still the puppy that is wagging it's tail. It's just doing the first, normal Dog-style wag before adding the Pointer-specific wiggle at the end. So it's the puppy instance of dog, doing the Dog version of Wag, who's code is defined in the implementation of the Dog class.

You may misunderstand that breakpoint/log statement, and think you're seeing the mother dog's wag method firing. That's not what's going on however.

Now, back to your problem.

Say view controller one is of type ParentVC, and view controller two is of type ChildVC, which inherits from ParentVC:

@interface ChildVC: ParentVC
...
@end

View Controller 2 is of type ChildVC, a subclass of view controller 1. When view controller 2 invokes [super viewdidAppear], it's invoking it in the code defined for the ParentVC class. That is not the same thing as invoking that method in view controller 1.

Look in the debug variable list and note the memory address of view controller 1 and view controller 2. When you break in your call to viewDidAppear, note the memory address of the object that's invoking the method.

When view controller 2 calls [super viewdidAppear], you'll see the code for defined in the ParentVC.m file running, but the object running that code is view controller 2.

like image 154
Duncan C Avatar answered Jan 03 '23 21:01

Duncan C