【问题标题】:How to Configure NSWindowController, NSViewController, and NSViews如何配置 NSWindowController、NSViewController 和 NSViews
【发布时间】:2014-07-26 02:58:31
【问题描述】:

说实话,我什至不知道从哪里开始。我觉得我一直在兜兜转转几个小时尝试不同的事情。

我的问题是如何在 IB 中配置 NSWindowControllers、NSViewControllers 和 NSViews,然后访问层次结构中的每一个以使用单个 NSWindowController 切换 NSViewControllers...

我从 Apple 网站上的这段代码开始,并试图改变它以适应我的情况: https://developer.apple.com/library/mac/samplecode/ViewController/Listings/MyWindowController_m.html#//apple_ref/doc/uid/DTS10004233-MyWindowController_m-DontLinkElementID_12

我有一个小应用程序,它有 2 个视图,需要根据用户交互来回切换。我们称它们为 drop_view 和 table_view。 Drop_view 是在启动时加载的视图。 我的两个视图都配置在单独的 nib 文件中:

RADropViewController.xib

  RADropViewController.m
  RADropViewController.h
  RADropView.m
  RADropView.h

RADropViewController.xib

  RADropViewController.m
  RADropViewController.h
  RADropView.m
  RADropView.h

每个 nib 都有一个文件所有者、第一响应者、应用程序、视图图标和对象。 File's Owner 设置为控制器类,View Icon 设置为 View 类,Object 图标设置为 View Controller 类。

然后我有一个带有窗口控制器的窗口控制器笔尖。

RAWindowController.xib

RAWindowController.h
RAWindowController.m

nib 的 File Owner 设置为 RAWindowController,Window 设置为 NSWindow,Object 设置为 RAWindowContoller。我在这个笔尖的窗口中也有一个自定义视图,因为在 Apple 示例中有一个 NSView 插座,我在所有研究中都在 stackoverflow 上读到“通常有一个带有主机视图的窗口控制器,用于托管不同的 NSWindowController)。

分店有:

文件的所有者

Outlets
    myTargetView -> Custom View
Referencing Outlets
   delegate -> Window - Window

窗口 - 窗口

Outlets
    delegate -> File's Owner
Referencing Outlets
    window -> Window Controller

窗口控制器

Outlets
    myTargetView -> Custom View
    window -> Window - Window

这是我的 RAWindowcontroller.h

@class RADropViewController, RATableViewController, RAWindowView;

@interface RAWindowController : NSWindowController
{

    IBOutlet NSView *myTargetView;
}

@property (nonatomic, assign) NSViewController *myCurrentViewController;

@property (nonatomic, strong) RADropViewController *dropViewController;
@property (nonatomic, strong) RATableViewController *tableViewController;

-(void)changeViewController:(NSInteger)whichViewTag;
- (NSViewController *)viewController;


@property (strong) IBOutlet NSView *myTargetView;
@end

还有我的 RAWindowController.m

#import "RAWindowController.h"
#import "RADropViewController.h"
#import "RATableViewController.h"

@interface RAWindowController ()

@end

@implementation RAWindowController

@synthesize myCurrentViewController, myTargetView;

enum // popup tag choices

{
    kDropView = 0,
    kTableView,
};

NSString *const kDropViewTitle    = @"RADropViewController";
NSString *const kTableViewTitle   = @"RATableViewController";

- (id)initWithWindow:(NSWindow *)window
{
    self = [super initWithWindow:window];
    if (self) {
    }
    return self;
}


-(void)awakeFromNib{
    _dropViewController = [[RADropViewController alloc] initWithNibName:kDropViewTitle bundle:nil];
    _tableViewController = [[RATableViewController alloc] initWithNibName:kTableViewTitle bundle:nil];
    [self changeViewController:kDropView];
    [myTargetView addSubview:[self.myCurrentViewController view]];
    [self.window center];
    [self.window setContentMaxSize:NSMakeSize(409.0, 295.0)];
    [self.window setContentMinSize:NSMakeSize(409.0, 295.0)];
}

-(void)windowWillLoad{
    [super windowWillLoad];
}

- (void)changeViewController:(NSInteger)whichViewTag
{
    if ([self.myCurrentViewController view] != nil)
    {
        [[self.myCurrentViewController view] removeFromSuperview];
    }
    switch (whichViewTag)
    {
        case kDropView:
        {
            if (self.dropViewController == nil)
            {
                _dropViewController = [[RADropViewController alloc] initWithNibName:kDropViewTitle bundle:nil];
            }
            myCurrentViewController = self.dropViewController;
            break;
        }
        case kTableView:
        {
            if (self.tableViewController == nil)
            {
               _tableViewController = [[RATableViewController alloc] initWithNibName:kTableViewTitle bundle:nil];
            }
            myCurrentViewController = self.tableViewController;
            break;
        }
    }
    [myTargetView addSubview:[self.myCurrentViewController view]];
}

- (NSViewController *)viewController
{
    return self.myCurrentViewController;
}

这是我的 drop_view 中的一些示例代码,当我想切换到我的 table_view 时调用它们

-(void)showDifferentViewController: (NSViewController *) controller{
    _windowController = [[RAWindowController alloc] initWithWindowNibName:@"RAWindowController"];
    [_windowController changeViewController:1];
}

所以一切正常,正如我在发布时所期望的那样。 drop_view 被加载,一切看起来都很好。 当我尝试加载 table_view 时,事情开始分崩离析。

这行代码:

[myTargetView addSubview:[self.myCurrentViewController view]];

是问题,至少在表面上是这样。 myTargetView 为零。启动时它不是零,但当我尝试加载新视图时它是零。所以没有新的视图被加载。我的 drop_view 只是呆在那里,什么也没发生。 myTargetView 代表我的主机视图(据我所知)。这是我的 nib 文件中窗口上的自定义视图。您可以在我的 RAWindowController.h 文件中看到它的出口设置,并且该连接对我来说看起来不错。似乎引用丢失可能是由于主机视图被卸载?

我想也许这篇文章救了我: How exactly does an NSView, an NSViewController, and MainMenu.xib fit together?

[self.window.contentView addSubview:self.customViewController.view];
[self.customViewController.view setFrame:[self.window.contentView bounds]];

...但我意识到我的 self.window 对象为零(我假设是因为我的 window 对象设置为 .nib 中的 NSWindowController)。

我有一种感觉,我没有掌握一些关于窗口、控制器、如何配置它们以及以编程方式访问它们的基本知识。 感谢您的任何见解。

【问题讨论】:

    标签: nsview nswindowcontroller nsviewcontroller


    【解决方案1】:

    好的,这就是我在提出您所链接的问题后的九个月里收集到的内容。每当您混合和匹配 nib、视图控制器和窗口控制器时,事情都会变得棘手。然而,如果你有积极的想法,数到三,敲木头,有时事情就会水到渠成。

    这就是我在心理上分解各种控制器的方式:

    NSWindowController (MyWindow.xib)
    |
    |-- NSViewController (MyFirstView.xib)
        |
        |-- NSView
            |
            |-- NSTextField
            |-- NSButton
            |-- NSImageView
            |-- Etc.
            |
    |-- NSViewController (MySecondView.xib)
        |
        |-- NSView
            |
            |-- NSTableView
            |-- NSButton
            |-- Etc.
    

    因此,根据您的情况,您需要在 RADropViewController.xib 中执行以下操作:

    1. 选择“文件的所有者”占位符对象。
    2. 转到 Identity Inspector 并确保 RADropViewController 是在“自定义类”字段中输入的类。
    3. 选择最顶层的视图对象。
    4. 再次在 Identity Inspector 中,确保 RADropView 是在“自定义类”字段中输入的类。
    5. 右键单击并从“文件所有者”对象拖动到自定义视图对象并连接view 出口。

    您现在已将视图控制器连接到其视图。通过在 RADropViewController.m 中执行以下操作,可以在代码中完成相同的操作:

    - (void)awakeFromNib
    {
        self.view = [[RADropView alloc] initWithFrame:NSMakeRect(0, 0, 250, 250)];
    }
    

    现在在 RATableViewController.xib(或 RATableViewController.m,如果您决定走代码路线)中重复这些步骤。

    为了清楚起见,您可以在 Interface Builder 中连接视图在代码中,但不能同时连接两者。我曾经不小心覆盖了我的视图,因为我会在 IB 中设置它们,然后在 -awakeFromNib 方法中再次设置它们。回想起来,我发现我基本上是在重做我在 Interface Builder 中所做的一切,但直到我真正掌握了 nib 解压过程,这似乎是一件合乎逻辑的事情。无论如何......回到乐趣。

    既然您的视图控制器都已设置完毕,请跳至 RAWindowController.xib。再次确保“文件所有者”对象指向您的窗口控制器类并将窗口连接到window 出口。

    RAWindowController.h 中,通过将 IBOutlet 宏关键字添加到您的视图控制器属性来使您的视图控制器出口:

    @property (nonatomic, strong) IBOutlet RADropViewController *dropViewController;
    @property (nonatomic, strong) IBOutlet RATableViewController *tableViewController;
    

    现在回到RAWindowController.xib,将两个视图控制器对象从对象浏览器拖到侧边栏。在 Identity Inspector 中,将每个的类设置为其各自的视图控制器类,并在 Attributes Inspector 中,将每个的 Nib Name 设置为您之前工作的 nib。现在,将视图控制器对象连接到您刚刚为其创建 outlet 的属性。

    最后,要切换视图,在 RAWindowController.m 中添加如下内容:

    - (void)changeViewController:(NSInteger)whichViewTag
    {
        NSView *contentView = self.window.contentView;
    
        switch (whichViewTag)
        {
            case kDropView:
            {
                self.myCurrentViewController = self.dropViewController;
                break;
            }
            case kTableView:
            {
                self.myCurrentViewController = self.tableViewController;
                break;
            }
        }
    
        if ( contentView.subviews.count > 0 )
        {
            [contentView replaceSubview:contentView.subviews[0]
                                   with:self.myCurrentViewController.view];
        } else {
            [contentView addSubview:self.myCurrentViewController.view];
        }
    }
    

    我现在很累,所以我可能错过了什么。然而,我不得不发布,看看我不久前是如何在这些东西上苦苦挣扎的。我希望我有一点帮助。如果我有什么不清楚的地方,请告诉我,我会尽力解释得更好。不过,我向你保证:最终一切都会变得有意义。有一天它会“点击”,你会嘲笑这个古老的 Stack Overflow 问题。无论如何,祝你好运,如果我能更清楚地说明你不确定的任何事情,请告诉我。放轻松。

    【讨论】:

    • Ben,非常感谢您回过头来根据您的经验提供如此详细的答案。我最终做了一些不同的事情,这似乎很有效,但将来会根据您的意见尝试我最初的设计理念。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多