Release of view controllers page 108


#1

Hi,
I have a question regarding the release of the view controllers page 108, just right after you add them into the viewControllers array.

Is it because the single controllers vc1 and vc2 are retained (reference counter has been increased) when added into the viewControllers array.
I will appreciate an explanation to confirm if I am on a correct track.

Thanks for nice book.
/petron


#2

Correct, any object added to an array is retained by that array. That array is then copied by the tab bar controller.


#3

I’ve got another question about these two view controllers we add to the tab bar controller array…

They are declared as follows:


UIViewController *vc1 = [[HypnosisViewController alloc] init];
UIViewController *vc2 = [[CurrentTimeViewController alloc] init];

Why isn’t vc1 declared as a HypnosisViewController and vc2 declared as a CurrentTimeViewController?

I get that the superclass of both HypnosisViewController and CurrentTimeViewController is UIViewController, and it doesn’t cause any build, link, or run time errors. But here’s what I don’t understand…

CurrentTimeViewController has additional instance variables when we subclassed (a UILabel that we use as an IBOutlet). So, it is a UIViewController… but on steroids (since it’s got more stuff). If we’re telling the linker “hey so I’ve got this UIViewController called vc2” and then all of a sudden we switch it up and go “So it’s a UIViewController, but allocate the memory for a CurrentTimeViewController,” shouldn’t that fubar something?

It’s kinda like declaring all your objects as “id’s” and then allocating as the “correct” object … at least in my head.

Is there a clear explanation for this? I’ve been wrestling with this one for a few weeks and don’t think I totally get it.


#4

You have to differentiate between the variable and the object that it points to.

By declaring a variable that points to a given object, it specifies nothing about the object it is pointing to. An object knows its type when it is created. (There is a hidden instance variable for every object called isa, when an object is created, the isa variable is set to the class that created it.)

Therefore, doing:

id vc = [[MyViewController alloc] init];

The object that vc points to is a MyViewController.

Similarly, doing:

NSString *vc = [[MyViewController alloc] init];

still works and vc points to a MyViewController - the object knows what it is, it doesn’t care what your variables call it. If you were escaping a burning building, and someone said, “Mike! Get that fire extinguisher!” You wouldn’t say, “My name’s not Mike, so I don’t know how to do that.” :slight_smile:

The issue only comes into play when you start sending messages to an object. To send a message to an object, you use a variable that points to that object as the receiver to the message. If you have an NSString * variable that points at a MyViewController and you try and send a message that MyViewController implements, you will get a warning from the compiler. However, your code will still execute okay.

Why? When you send a message to an object, the method that is triggered isn’t figured out until runtime. (This allows us to do all kinds of fancy stuff that a language like C or C++ can’t do.) When a message is sent to an object during execution, that object looks at its isa variable and then asks the class stored in the isa variable to run the method that matches the message. (It also sets self = that object.)

Therefore, the type of a variable in code is only a hint to a compiler. We purposely type our variables to the object it points to so that, at compile-time, we can see any possible errors. We won’t truly know if there is an error until runtime, though.

In the specific case you are showing, we aren’t sending any HypnosisViewController- or CurrentTimeViewController-specific messages to vc1 or vc2. Thus, we don’t need to reference them by their true type. Using id here would have the same effect.


#5

Great response. Extremely clear.

Consider my mind blown. :slight_smile: Mike, can you help me scoop the pieces back up and grab some duct tape?


#6

Ok, just because you can (get away with it), doesn’t mean you should.

For clarity’s sake, for consistency’s sake, for the sake of good coding practice, for the love of God, shouldn’t you declare your object’s pointer variable as the same type as the type of object you are instantiating? I can imagine that there could be a special reasons for declaring it as an id type, but come on. vc1 and vc2 should have been declared such…

	HypnosisViewController    *vc1 = [[HypnosisViewController    alloc] init];
	CurrentTimeViewController *vc2 = [[CurrentTimeViewController alloc] init];

#7

In this case, we aren’t really “getting away” with anything; both vc1 and vc2 are instances of UIViewController. From the perspective of this chunk of code, the only thing that matters is that these two objects are instances of UIViewController, because we are putting them in an array to set as the viewControllers property of a UITabBarController.

This is fairly common when we are dealing with a set of objects who all share a superclass and we are only sending messages to these objects that the superclass implements.