如何配置NSWindowController,NSViewController和NSViews

Ric*_*ers 3 nsview nsviewcontroller nswindowcontroller

说实话,我甚至不知道从哪里开始.我觉得我已经在圈子里走了好几个小时尝试不同的事情.

我的问题是如何在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
Run Code Online (Sandbox Code Playgroud)

RADropViewController.xib

  RADropViewController.m
  RADropViewController.h
  RADropView.m
  RADropView.h
Run Code Online (Sandbox Code Playgroud)

每个笔尖都有一个文件所有者,第一响应者,应用程序,视图图标和对象.File的Owner设置为控制器类,View Icon设置为View类,Object图标设置为View Controller类.

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

RAWindowController.xib

RAWindowController.h
RAWindowController.m
Run Code Online (Sandbox Code Playgroud)

nib将文件所有者设置为RAWindowController,将Window设置为NSWindow,将对象设置为RAWindowContoller.我在这个笔尖的窗口中也有一个自定义视图,因为在Apple示例中有一个NSView插座,我在所有研究中读取了stackoverflow,"通常有一个带有主机视图的窗口控制器,用于托管不同的NSWindowControllers).

网点是:

文件的所有者

Outlets
    myTargetView -> Custom View
Referencing Outlets
   delegate -> Window - Window
Run Code Online (Sandbox Code Playgroud)

窗口 - 窗口

Outlets
    delegate -> File's Owner
Referencing Outlets
    window -> Window Controller
Run Code Online (Sandbox Code Playgroud)

窗口控制器

Outlets
    myTargetView -> Custom View
    window -> Window - Window
Run Code Online (Sandbox Code Playgroud)

这是我的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
Run Code Online (Sandbox Code Playgroud)

和我的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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

所以一切都按照我的预期发布.drop_view被加载并且看起来都很好.当我尝试加载table_view时,事情开始分崩离析.

这行代码:

[myTargetView addSubview:[self.myCurrentViewController view]];
Run Code Online (Sandbox Code Playgroud)

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

我想也许这篇文章救了我: NSView,NSViewController和MainMenu.xib究竟是如何组合在一起的?

[self.window.contentView addSubview:self.customViewController.view];
[self.customViewController.view setFrame:[self.window.contentView bounds]];
Run Code Online (Sandbox Code Playgroud)

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

我有一种感觉,我没有掌握关于Windows,控制器,如何配置它们以及以编程方式访问它们的非常基本的东西.我很欣赏你的任何见解.

Ben*_*ock 8

好的,所以这就是我在问你关联的问题后的九个月里我所接受的.无论何时混合和匹配笔尖,视图控制器和窗口控制器,事情都会变得毛茸茸.但是,如果你认为积极的想法,数到三,并敲木头,有时事情就会落到实处.

这就是我在精神上打破各种控制器的方式:

NSWindowController (MyWindow.xib)
|
|-- NSViewController (MyFirstView.xib)
    |
    |-- NSView
        |
        |-- NSTextField
        |-- NSButton
        |-- NSImageView
        |-- Etc.
        |
|-- NSViewController (MySecondView.xib)
    |
    |-- NSView
        |
        |-- NSTableView
        |-- NSButton
        |-- Etc.
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

现在您的视图控制器都已设置完毕,请跳转到RAWindowController.xib.再次确保"文件所有者"对象指向您的窗口控制器类并将窗口连接到window插座.

RAWindowController.h中,通过将IBOutletmacro关键字添加到视图控制器属性来创建视图控制器插座:

@property (nonatomic, strong) IBOutlet RADropViewController *dropViewController;
@property (nonatomic, strong) IBOutlet RATableViewController *tableViewController;
Run Code Online (Sandbox Code Playgroud)

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

最后,要切换视图,请将这样的内容添加到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];
    }
}
Run Code Online (Sandbox Code Playgroud)

我现在很累,所以我可能错过了一些东西.然而,我不得不发帖,看看我不久前是如何与这些东西挣扎的.我希望我能帮助一点.如果我不清楚任何事情,请告诉我,我会尝试更好地解释.不过我向你保证:最终都会有意义.有一天它只是"点击",你会嘲笑这个旧的Stack Overflow问题.祝你好运,如果我能更清楚地了解你不确定的事情,请告诉我.别紧张.