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.)
id vc = [[MyViewController alloc] init];
The object that vc points to is a MyViewController.
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.”
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.