如何配置NSWindowController, NSViewController和NSViews

时间:2023-01-24 08:40:38

To be honest, I don't even know where to start. I feel like I've been going around in circles for hours trying different things.

老实说,我甚至不知道从哪里开始。我觉得我好像在兜圈子里转了几个小时,尝试不同的东西。

My issues are around how to configure NSWindowControllers, NSViewControllers, and NSViews in IB and then access each in a hierarchy to switch out the NSViewControllers using a single NSWindowController...

我的问题是如何在IB中配置nswindowcontrollernsviewcontrollerandnsviewcontrollerandnsviews,然后在层次结构中访问它们,使用一个NSWindowController来切换nsviewcontrollerde…

I started with this code from the Apple site and am trying to alter it to fit my situation: https://developer.apple.com/library/mac/samplecode/ViewController/Listings/MyWindowController_m.html#//apple_ref/doc/uid/DTS10004233-MyWindowController_m-DontLinkElementID_12

我从苹果网站开始使用这段代码,并试图修改它,以适应我的情况:https://developer.apple.com/library/mac/samplecode/ViewController/Listings/MyWindowController_m.html#/ apple_ref/doc/ dts10004233 - mywindowcontroller_m - dontlinkelamed - 12

I have a small app that has 2 views that need to be switched back and forth depending on user interaction. Let's call them drop_view and table_view. Drop_view is the view that is loaded on launch. Both of my views are configured in separate nib files:

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

RADropViewController.xib

RADropViewController.xib

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

RADropViewController.xib

RADropViewController.xib

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

Each nib has a File's Owner, First Responder, Application, View Icon, and Object. The File's Owner is set to the controller class, the View Icon is set to the View class, and the Object icon is set to the View Controller class.

每个nib都有一个文件的所有者、第一响应器、应用程序、视图图标和对象。文件的所有者设置为控制器类,视图图标设置为视图类,对象图标设置为视图控制器类。

Then I have a window controller nib with a window controller.

然后我有一个窗口控制器nib和一个窗口控制器。

RAWindowController.xib

RAWindowController.xib

RAWindowController.h
RAWindowController.m

The nib has File Owner set to RAWindowController, Window set to NSWindow, and an Object set to RAWindowContoller. I also have a Custom View in the window in this nib because there is an NSView outlet in the Apple example and I read on * in all of my research that "there is usually a window controller with a host view and which is used to host the different NSWindowControllers).

nib将文件所有者设置为RAWindowController,将窗口设置为NSWindow,并将对象设置为RAWindowContoller。我也有一个自定义视图的窗口在这笔尖,因为有一个NSView出口苹果的例子和我读*我所有的研究中,通常有一个窗口与宿主视图和控制器用于主机不同NSWindowControllers)。

The outlets are:

媒体有:

File's Owner

文件的所有者

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

Window - Window

窗口,窗口

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

Window Controller

窗口控制器

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

Here is my RAWindowcontroller.h

这是我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

and my RAWindowController.m

和我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;
}

Here is some sample code from my drop_view that I call when I want to switch to my table_view

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

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

So everything works as I would expect on launch. The drop_view gets loaded and all looks good. Things start to fall apart when I try to load the table_view.

所以一切都按照我的预期运行。drop_view被加载,一切看起来都很好。当我试图加载table_view时,事情开始崩溃。

This line of code:

这行代码:

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

is the issue, at least on the surface. myTargetView is nil. It's not nil on launch but is nil when I try to load a new view. So no new view gets loaded. My drop_view just stays there as nothing happened. myTargetView represents my host view (as I understand it). It's the custom view on my window in my nib file. You can see the outlet to it set up in my RAWindowController.h file and that connection looks OK to me. It seems like the reference is being lost maybe due to the host view being unloaded?

至少在表面上是如此。myTargetView是零。当我尝试加载一个新视图时,它不是nil,而是nil。因此不会加载新视图。我的drop_view不会出现任何问题。myTargetView表示我的主机视图(正如我理解的那样)。它是nib文件中窗口的自定义视图。你可以在我的RAWindowController中看到它的outlet。h文件和那个连接在我看来没问题。似乎是由于主机视图被卸载而丢失了引用?

I thought maybe this post had saved me: How exactly does an NSView, an NSViewController, and MainMenu.xib fit together?

我以为这篇文章救了我:NSView, NSViewController和MainMenu到底是怎么回事。xib组合在一起?

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

...but I realized my self.window object is nil (I'm assuming because my window object is set to an NSWindowController in the .nib).

…但我意识到了我自己。窗口对象为nil(我假设因为我的窗口对象被设置为.nib中的nswindow控制器)。

I have a feeling I'm failing to grasp something very basic about windows, controllers, how to configure them, and to access them programmatically. I appreciate any insight you have.

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

1 个解决方案

#1


6  

Okay, so here's what I've picked up in the nine months since I asked the question you linked to. Anytime you're mixing and matching nibs, view controllers, and window controllers, things can get hairy. However, if you think positive thoughts, count to three, and knock on wood, sometimes things will fall into place.

好吧,这是我在9个月里学到的自从我问了你相关的问题。任何时候,当你混合和匹配nib、视图控制器和窗口控制器时,事情就会变得很麻烦。然而,如果你有积极的想法,数到三,敲木头,有时事情就会发生。

This is how I mentally break down the various controllers:

这就是我在精神上分解各种控制器的方法:

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

So in your situation, you'll want to do the following in RADropViewController.xib:

在你的情况下,你需要在radropviewcontroller中执行以下操作:

  1. Select the "File's Owner" placeholder object.
  2. 选择“文件的所有者”占位符对象。
  3. Go to the Identity Inspector and make sure that RADropViewController is the class entered in the "Custom Class" field.
  4. 转到标识检查器,并确保RADropViewController是在“自定义类”字段中输入的类。
  5. Select your top-most view object.
  6. 选择最顶部的视图对象。
  7. Again in the Identity Inspector, make sure that RADropView is the class entered in the "Custom Class" field.
  8. 同样,在标识检查器中,确保RADropView是在“自定义类”字段中输入的类。
  9. Right-click and drag from the "File's Owner" object to custom view object and connect the view outlet.
  10. 右键单击并从“File's Owner”对象拖拽到自定义视图对象并连接视图输出。

You've now connected the view controller to its view. The same thing can be done in code by doing the following in RADropViewController.m:

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

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

Now repeat these steps in RATableViewController.xib (or RATableViewController.m if you decide to go the code route).

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

Just to be clear, you either connect the view in Interface Builder or in code, but not both. I used to accidentally override my views because I would set them in IB and then again in the -awakeFromNib method. Looking back, I see that I was basically redoing everything I did in Interface Builder, but until I really grasped the nib unarchiving process, it seemed like a logical thing to do. Anyway … back to the fun.

需要说明的是,您要么在接口构建器中连接视图,要么在代码中连接视图,但不是两者都连接。我经常不小心覆盖我的视图,因为我要在IB中设置它们,然后再在-awakeFromNib方法中设置它们。回顾过去,我发现我基本上是在重做我在接口构建器中所做的一切,但是直到我真正理解了nib unarchiving过程,这似乎是一件合乎逻辑的事情。不管怎样,回到乐趣上来。

Now that your view controllers are all set up, hop over to RAWindowController.xib. Again, make sure the "File's Owner" object is pointing to your window controller class and connect the window to the window outlet.

现在已经设置好了视图控制器,请跳到RAWindowController.xib。同样,确保“文件的所有者”对象指向窗口控制器类,并将窗口连接到窗口outlet。

In RAWindowController.h, make your view controllers outlets by adding the IBOutlet macro keyword to your view controller properties:

在RAWindowController。h,通过将IBOutlet宏关键字添加到视图控制器属性,使您的视图控制器outlet:

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

Now back in RAWindowController.xib, drag two view controller objects from the Object Browser to the sidebar. In the Identity Inspector, set the class for each to its respective view controller class and in the Attributes Inspector, set the Nib Name for each to the nibs you worked earlier. Now, connect the view controller objects to the properties you just created outlets for.

现在回到RAWindowController。xib,将两个视图控制器对象从对象浏览器拖到工具条。在Identity Inspector,将每个类设置为其各自的视图控制器类,在Attributes Inspector,将每个类的Nib名称设置为您之前工作过的Nib。现在,将视图控制器对象连接到刚才创建的outlet属性。

Finally, to switch the views, add something like this to RAWindowController.m:

最后,切换视图,将如下内容添加到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];
    }
}

I'm pretty tired right now, so I may have missed something. I had to post, however, seeing as how I was struggling with this stuff not too long ago. I hope I've helped a little. If I was unclear about anything, please let me know, and I'll try to explain things better. I promise you this much, though: it will all make sense eventually. One day it'll just "click," and you'll laugh at this old Stack Overflow question. Anyway, good luck, and let me know if I can shed more light on anything you're unsure of. Take it easy.

我现在很累,所以可能漏掉了什么。然而,我不得不在网上发帖,看看不久前我是如何与这些东西做斗争的。我希望我帮了一点忙。如果我有什么不清楚的地方,请告诉我,我会尽量解释得更好。不过,我向你保证,这一切最终都会有意义的。总有一天它会“点击”,你会嘲笑这个老的堆栈溢出问题。无论如何,祝你好运,如果你不确定的话,请让我知道。不要着急。

#1


6  

Okay, so here's what I've picked up in the nine months since I asked the question you linked to. Anytime you're mixing and matching nibs, view controllers, and window controllers, things can get hairy. However, if you think positive thoughts, count to three, and knock on wood, sometimes things will fall into place.

好吧,这是我在9个月里学到的自从我问了你相关的问题。任何时候,当你混合和匹配nib、视图控制器和窗口控制器时,事情就会变得很麻烦。然而,如果你有积极的想法,数到三,敲木头,有时事情就会发生。

This is how I mentally break down the various controllers:

这就是我在精神上分解各种控制器的方法:

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

So in your situation, you'll want to do the following in RADropViewController.xib:

在你的情况下,你需要在radropviewcontroller中执行以下操作:

  1. Select the "File's Owner" placeholder object.
  2. 选择“文件的所有者”占位符对象。
  3. Go to the Identity Inspector and make sure that RADropViewController is the class entered in the "Custom Class" field.
  4. 转到标识检查器,并确保RADropViewController是在“自定义类”字段中输入的类。
  5. Select your top-most view object.
  6. 选择最顶部的视图对象。
  7. Again in the Identity Inspector, make sure that RADropView is the class entered in the "Custom Class" field.
  8. 同样,在标识检查器中,确保RADropView是在“自定义类”字段中输入的类。
  9. Right-click and drag from the "File's Owner" object to custom view object and connect the view outlet.
  10. 右键单击并从“File's Owner”对象拖拽到自定义视图对象并连接视图输出。

You've now connected the view controller to its view. The same thing can be done in code by doing the following in RADropViewController.m:

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

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

Now repeat these steps in RATableViewController.xib (or RATableViewController.m if you decide to go the code route).

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

Just to be clear, you either connect the view in Interface Builder or in code, but not both. I used to accidentally override my views because I would set them in IB and then again in the -awakeFromNib method. Looking back, I see that I was basically redoing everything I did in Interface Builder, but until I really grasped the nib unarchiving process, it seemed like a logical thing to do. Anyway … back to the fun.

需要说明的是,您要么在接口构建器中连接视图,要么在代码中连接视图,但不是两者都连接。我经常不小心覆盖我的视图,因为我要在IB中设置它们,然后再在-awakeFromNib方法中设置它们。回顾过去,我发现我基本上是在重做我在接口构建器中所做的一切,但是直到我真正理解了nib unarchiving过程,这似乎是一件合乎逻辑的事情。不管怎样,回到乐趣上来。

Now that your view controllers are all set up, hop over to RAWindowController.xib. Again, make sure the "File's Owner" object is pointing to your window controller class and connect the window to the window outlet.

现在已经设置好了视图控制器,请跳到RAWindowController.xib。同样,确保“文件的所有者”对象指向窗口控制器类,并将窗口连接到窗口outlet。

In RAWindowController.h, make your view controllers outlets by adding the IBOutlet macro keyword to your view controller properties:

在RAWindowController。h,通过将IBOutlet宏关键字添加到视图控制器属性,使您的视图控制器outlet:

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

Now back in RAWindowController.xib, drag two view controller objects from the Object Browser to the sidebar. In the Identity Inspector, set the class for each to its respective view controller class and in the Attributes Inspector, set the Nib Name for each to the nibs you worked earlier. Now, connect the view controller objects to the properties you just created outlets for.

现在回到RAWindowController。xib,将两个视图控制器对象从对象浏览器拖到工具条。在Identity Inspector,将每个类设置为其各自的视图控制器类,在Attributes Inspector,将每个类的Nib名称设置为您之前工作过的Nib。现在,将视图控制器对象连接到刚才创建的outlet属性。

Finally, to switch the views, add something like this to RAWindowController.m:

最后,切换视图,将如下内容添加到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];
    }
}

I'm pretty tired right now, so I may have missed something. I had to post, however, seeing as how I was struggling with this stuff not too long ago. I hope I've helped a little. If I was unclear about anything, please let me know, and I'll try to explain things better. I promise you this much, though: it will all make sense eventually. One day it'll just "click," and you'll laugh at this old Stack Overflow question. Anyway, good luck, and let me know if I can shed more light on anything you're unsure of. Take it easy.

我现在很累,所以可能漏掉了什么。然而,我不得不在网上发帖,看看不久前我是如何与这些东西做斗争的。我希望我帮了一点忙。如果我有什么不清楚的地方,请告诉我,我会尽量解释得更好。不过,我向你保证,这一切最终都会有意义的。总有一天它会“点击”,你会嘲笑这个老的堆栈溢出问题。无论如何,祝你好运,如果你不确定的话,请让我知道。不要着急。