使用Interface Builder创建的自定义视图在其他视图中调用时不会呈现

Col*_*iot 11 xcode objective-c interface-builder

我有一个主窗口的xib,我在以下步骤中创建了一个自定义视图:

  1. 创建一个继承自的新类NSView.

MyView.h:

    #import <Cocoa/Cocoa.h>
    IB_DESIGNABLE
    @interface MyView : NSTableCellView
    @end
Run Code Online (Sandbox Code Playgroud)

MyView.m:

    #import "MyView.h"

    @implementation MyView

    - (void)awakeFromNib {
        NSLog(@"Post view awaking from nib.");
    }

    @end
Run Code Online (Sandbox Code Playgroud)
  1. 创建一个新的xib,并将根视图的类设置为上面创建的类.并设计在那个xib中.
  2. 设置从xib到班级的出口.

我尝试在主窗口中使用此自定义视图,执行以下步骤:

  1. 将自定义视图拖动到主窗口的xib.
  2. 将该自定义视图的类设置为上面创建的类.

但没有任何东西呈现.从日志中,我可以看到awakeFromNib自定义视图类中的代码已执行.当我将类设置IB_DESIGNABLE为时,视图在主窗口的xib中变空,与我设计的不同.

我尝试将自定义视图的xib的文件所有者设置为自定义类,但没有任何更改.

我想问题是,自定义视图的xib文件实际上并未加载.当我用谷歌搜索它时,似乎很少有关于这个确切主题的参考文献.那么,我该如何实现这一目标呢?即,在IB中设计一个视图,在类中实现它的方法,将这两个方法关联起来,并将其公开,就像系统视图一样,用于其他xibs?

更新:

我找到了一个教程,并意识到我缺少的东西(在构建时正确渲染视图).我必须从xib中的视图添加一个插座到视图类:

@property (nonatomic, strong) IBOutlet NSView *view;
Run Code Online (Sandbox Code Playgroud)

,然后在(id)initWithCoder:(NSCoder *)coder方法中加载它.

[[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self topLevelObjects:nil];
[self addSubview:self.view];
Run Code Online (Sandbox Code Playgroud)

但是视图仍然不会在界面构建器中呈现.

rob*_*off 3

您的猜测是正确的:xib 没有被加载。nib 加载程序不知道您的自定义视图的 nib。nib 框架不提供定义该连接的工具,因此您需要编写代码来加载 xib。

这就是我要做的。将contentView属性添加到您的自定义视图:

@interface MyView ()

@property (nonatomic, strong, readwrite) IBOutlet NSView *contentView;

@end
Run Code Online (Sandbox Code Playgroud)

在自定义视图的笔尖中,将根视图的自定义类设置回NSView并断开与它的所有(不再有效)插座连接。将文件所有者的自定义类设置为您的自定义类名(例如MyView)。将根视图连接到文件所有者的contentView出口,并将文件所有者的所有其他出口连接到笔尖中的相应对象。

然后在自定义视图子类中实现awakeFromNib以加载笔尖并将内容视图添加为子视图:

@implementation MyView {
    BOOL hasLoadedOwnNib: 1;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    [self loadOwnNibIfNeeded];
}

- (void)loadOwnNibIfNeeded {
    if (hasLoadedOwnNib) {
        return;
    }

    hasLoadedOwnNib = YES;

    [[NSBundle bundleForClass:self.class] loadNibNamed:NSStringFromClass(self.class) owner:self topLevelObjects:nil];
    self.contentView.frame = self.bounds;
    self.contentView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
    [self addSubview:self.contentView];
}

@end
Run Code Online (Sandbox Code Playgroud)

请注意,您必须小心不要允许无限递归。当您的应用程序加载主窗口的 nib 时,它将创建一个实例MyView并(最终)发送它awakeFromNib。然后, inawakeFromNib加载MyView它自己的笔尖,它是文件的所有者。nib 加载器发送awakeFromNib到文件的所有者,这将在您已经处于-[MyView awakeFromNib]. 如果不检查这一点,则会由于无限递归而导致堆栈溢出。