当父 UIViewController 设置为 RootViewController 时,UIView 不会成为第一响应者



我正在写BNR的iOS编程书的第7章,我遇到了一个问题。 在本章的开头,我设置了一个UIView控制器(HypnosisViewController),其中包含一个UIView(HypnosisView),以响应上一章中的运动事件。

我在 AppDelegate.m 文件中创建了 UIViewController:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ...
    HypnosisViewController *hvc = [[HypnosisViewController alloc] init];
    [[self window] setRootViewController:hvc];
    ...
}

在 HypnosisViewController 中,我将 HypnosisView 设置为第一响应者:

- (void)loadView
{
    // Create a view
    CGRect frame = [[UIScreen mainScreen] bounds];
    HypnosisView *view = [[HypnosisView alloc] initWithFrame:frame];
    [self setView:view];
    [view becomeFirstResponder];
}

在催眠视图中,我确保将"是"返回为canBebeResponder。 不幸的是,催眠视图没有像以前那样对运动事件做出反应。 当我最终继续前进时,我有一个有趣的发现。 如果我将 HypnosisViewController 移动到 UITabBarController 中,HypnosisView 就会开始响应运动事件。 代码如下所示:

HypnosisViewController *hvc = [[HypnosisViewController alloc] init];
UITabBarController *tabBarController = [[UITabBarController alloc] init];
NSArray *viewControllers = [NSArray arrayWithObjects:hvc, <insert more objs here>, nil];
[tabBarController setViewControllers:viewControllers];
[[self window] setRootViewController:tabBarController]; 

为什么当HypnosisViewController设置为RootViewController时,HypnosisView没有成为第一响应者? 为什么一旦HypnosisViewController被放置在另一个控制器中,它就会开始工作? 关于 RootViewController,我缺少什么?

谢谢!

你的问题非常贴切。我也在学习同一本书,并且在同一章。问题是,在使用UITabBarController之前,我们要么使用HypnosisViewController,要么使用TimeViewController。然后,我们将在AppDelegate.m文件中执行[self.window setRootViewController:hvc]或[self.window setRootViewController:tvc]。在这种情况下,setRootViewController 方法在内部调用 loadView 方法。因此,如果应该调用 loadView,那么成为第一响应者(根据您的代码作为方法调用驻留在其中)也应该被触发。所以在内部可以成为第一响应者应该被调用 现在,当我们使用UITabBarController时,事情往往会中断。发生的情况不是通过代码行"[[self window] setRootViewController:tabBarController];"调用loadView,而是通过"[tabBarController setViewControllers:viewControllers];"调用。因此,底线是rootViewController属性(当设置为tabBarController时)不调用loadView方法,因此不会调用"bebe成为FirstResponder"。你可能会争辩说,loadView确实是通过'[tabBarController setViewControllers:viewControllers]'调用的,但setViewControllers不用于设置根视图控制器。 当我遇到这个问题时,我明确呼吁成为第一响应者。方法如下:-

@implementation HypnoTimeAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions //method of UIApplicationDelegate protocol  
{
    NSLog(@"lets begin");
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    HypnosisViewController *viewController= [[HypnosisViewController alloc] init];
    TimeViewController *viewController2= [[TimeViewController alloc] init];

    NSLog(@"view controllers are done initializing!");
    UITabBarController *tabBarController= [[UITabBarController alloc] init];
    NSArray *viewControllers= [NSArray arrayWithObjects:viewController,viewController2, nil];
    [tabBarController setViewControllers:viewControllers];//loadView of HypnosisViewController gets called internally since the 'app view' isn't going to load from a XIB file but from 'HypnosisView.m'.loadView method of TimeViewController loads its own view from the XIB file.
    [self.window setRootViewController:tabBarController];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}
@implementation HypnosisViewController
 -(void)loadView{
    NSLog(@"HypnosisView loading...");
    HypnosisView *myView= [[HypnosisView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.view= myView;
    [self configureFirstResponder];//configuring first responder
}

-(void) configureFirstResponder{
        BOOL viewDidBecomeFirstResponder= [self.view becomeFirstResponder];
        NSLog(@"Is First Responder set as HypnosisView? %i",viewDidBecomeFirstResponder);
    }

最新更新