1

我查看了其他 SO 问题,但看不到我需要的帮助:我有一个 Cocoa 应用程序,其 NSViewControllers 子类在 NSTabView 中。

一切正常,除了 - 当我第一次运行应用程序时,Tab 0 内容不显示。当我选择选项卡 1,然后选项卡 0,选项卡 1 显示,选项卡 0 显示正常。

我需要一些关于如何初始化选项卡视图的建议,因为我想我正在做一些奇怪的事情。

到目前为止,这就是我正在做的事情:

    - (void)windowDidLoad
    {

        NSLog(@"%s", __FUNCTION__);
        NSViewController *newController = nil;
        newController = [[FirstViewController alloc]
                         initWithNibName:@"FirstViewController" bundle:nil];
        NSTabViewItem *item;
        [[self aTabView] selectFirstTabViewItem:newController];
        newController.view.frame = aTabView.contentRect;
        [item setView:firstViewController.view];
        self.currentViewController = newController;
    }

更新,彼得·霍西(Peter Hosey)发表了很好的评论,我的工作代码如下:

- (void)windowDidLoad
{

    NSLog(@"%s", __FUNCTION__);

    firstViewController = [[FirstViewController alloc]
                     initWithNibName:@"FirstViewController" bundle:nil];

    secondViewController = [[SecondViewController alloc]
                                       initWithNibName:@"SecondViewController" bundle:nil];
    thirdViewController = [[ThirdViewController alloc]
                                        initWithNibName:@"ThirdViewController" bundle:nil];

    NSTabViewItem *item;
    if (firstViewController != nil) {
        item = [aTabView tabViewItemAtIndex:0];
        [item setView:[[self firstViewController] view]];
        //[firstViewController.view.frame = aTabView.contentRect];
        self.currentViewController = firstViewController;
    }
}




- (BOOL)switchViewController:(NSTabView*)tabView item:(NSTabViewItem*)nextItem {
    NSLog(@"%s", __FUNCTION__);
    NSViewController *newController = nil;
    newController.view = NO;
    // assume a different identifier has been assigned to each tab view item in IB
     itemIndex = [tabView indexOfTabViewItemWithIdentifier:[nextItem identifier]];
    switch (itemIndex) {
        case 0:
            newController = firstViewController;
            break;
        case 1:
            newController = secondViewController;
            break;
        case 2:
            newController = thirdViewController;
            break;
    }
    if (newController != nil) {
        [nextItem setView:newController.view];
         newController.view.frame = tabView.contentRect;
        self.currentViewController = newController; 

        /*
         NSLog(@"%s: myTabView.contentRect=%@ currentViewController.view.frame=%@",
              __FUNCTION__, NSStringFromRect(aTabView.contentRect),
              NSStringFromRect(currentViewController.view.frame));
         */
        return YES;
    }
    else {
        // report error to user here
        NSLog(@"Can't load view for tab %ld", (long)itemIndex);
        return NO;
    }
}

- (BOOL)tabView:(NSTabView*)tabView shouldSelectTabViewItem:(NSTabViewItem*)tabViewItem {
    return [self switchViewController:tabView item:tabViewItem];
}
4

1 回答 1

2
    NSViewController *newController = nil;
    newController = [[FirstViewController alloc]
                     initWithNibName:@"FirstViewController" bundle:nil];

该声明和语句可以合并为一个带有初始化器的声明。

在你的initwindowDidLoad方法中这样做是没有意义的;您创建两个单独的 FirstViewControllers。

    NSTabViewItem *item;

您永远不会创建 NSTabViewItem 并将其分配给此变量。如果您希望您的selectFirstTabViewItem:消息这样做,(1)不,那不是它所做的,并且(2)它不可能这样做,因为它不知道您的变量,甚至不知道您有一个。

在 ARC 下,此变量被隐式初始化为nil,因此所有后续尝试在此处使用项目的消息都将不执行任何操作。如果您没有使用 ARC,则无法初始化此变量将在您尝试使用它时导致(可能是间歇性的)崩溃。

     [[self aTabView] selectFirstTabViewItem:newController];

在这里传递你闪亮的新视图控制器(其中一个)不会像我认为的那样做。

selectFirstTabViewItem:是一个动作方法;它的参数是消息的发送者,一般应该是控件或菜单​​项。当您将其设置为按钮、菜单项等的操作时,该按钮/菜单项/无论什么都将是发送者。

将视图控制器作为发送者传递是没有意义的。此外,selectFirstTabViewItem:不会更改第一个选项卡视图项目(如果有的话)的任何内容,并且它绝对不会假设或检查其发送者是 VC,如果是,则将项目的视图设置为 VC 的视图。它选择第一个选项卡视图项(使其成为当前选项卡),仅此而已。

最有可能的是,这种方法忽略了它的论点。如果要将第一个选项卡视图项的视图设置为 VC 的视图,则必须自己进行。当然,您必须首先获取(或创建)选项卡视图项。

    [item setView:firstViewController.view];

在 ARC 下,这无济于事。在 MRC 下,它可能会崩溃(见上文)。

你需要做什么

我假设这段代码来自一个 NSWindowController 子类。我进一步假设这个 WC 有一个笔尖。

  • 确保这aTabView是一个插座,并且连接在 WC 的笔尖中。应该是一个用关键字aTabView声明的简单属性。IBOutlet不要为它实现任何自定义访问器方法;只需声明该属性,将其连接到 nib 中,然后在您的代码中访问它。
  • 在一个地方创建您的视图控制器, 并确保你只做一次(不是在 and 中或两者initWithWindow:windowDidLoad. 您可以在窗口控制器的 nib 中创建所有 VC。不要忘记设置它们的类名(如果你有它们的 NSVC 子类)和 nib 名称。
  • 在 nib 中创建的选项卡视图将具有至少一个选项卡视图项。我建议在那里创建所有项目,并在运行时简单地替换他们的视图(用 VC 的视图)。
  • 您应该将标签视图的项目替换为windowDidLoad. 确保窗口未设置为最初可见;只有在至少填充了第一个选项卡视图项之后,您才会想要显示它。

关于在 nib 中创建的选项卡视图的一个注释:最初可见的项目(选项卡)是您在 nib 中可见的项目。确保在保存之前将选项卡视图切换回其第一个选项卡。

于 2013-06-20T20:49:22.473 回答