Cocoa-Touch internals: How does the view know its controller?
If you add a subview to a view or add a view to a window, how does iOS know which controller this view belongs too?
Easy example:
Have a UI开发者_开发知识库View without UIViewController
and add it to the window [window addSubView:myView]
--> it will not rotate.
Now use a UIViewController
, have it implement shouldAutoRotateToInterfaceOrientation:
and add the controller's view to the window: [window addSubView:myController.view]
--> magically, the view will adjust to interface orientation.
But look at the code: in both cases a UIView
was added. How can iOS possibly be aware that in the second case a UIViewController
was involved?
I'm interested in how this is done internally. My best guess is that UIViewController.view
is a setter which adds the controller to an internal array of controllers or assigns itself to some internal variable which holds the currently active controller.
Simple. Look in UIView.h
. It's right there. Each UIView
has a pointer back to a UIViewController
(which is apparently referred to as the "viewDelegate").
Dave DeLong is correct (and gets +1) as it is clearly defined UIView.h as @package so anything in UIKit can access it.
Here is an example of accessing that variable for educational purposes only (obviously you will not do this in a real application).
SomeAppDelegate.m
@synthesize navigationController=_navigationController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
//DO NOT TRY THIS AT HOME
UIView *mynavview = self.navigationController.view;
//Guaranteed _viewDelegate atleast in iOS 4.3
Ivar ivar = class_getInstanceVariable([UIView class], "_viewDelegate");
UIViewController *controller = object_getIvar(mynavview, ivar);
NSLog(@"controller = self.navigationController? %@", controller == self.navigationController ? @"Yes" : @"No");
return YES;
}
UIViewController has a private class method (called controllerForView:
, I believe) which is used to find the view's controller. Internally, there is probably a table used to connect the two together, and this method simply finds the proper location in that table and returns its value. When the result is nil, the default implementation will be used (don't rotate).
If you want to be sure about the name of the method, set a breakpoint in -[UIView becomeFirstResponder]
, tap on a text field, and step through the code until it shows up in the call stack. I suggest using becomeFirstResponder
because it is easier to control than most things which get the view controller.
精彩评论