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

时间:2015-10-25 11:43:01

标签: objective-c xcode interface-builder

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

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

    MyView.h

        #import <Cocoa/Cocoa.h>
        IB_DESIGNABLE
        @interface MyView : NSTableCellView
        @end
    

    MyView.m

        #import "MyView.h"
    
        @implementation MyView
    
        - (void)awakeFromNib {
            NSLog(@"Post view awaking from nib.");
        }
    
        @end
    
    1. 创建一个新的xib,并将根视图的类设置为上面创建的类。并设计在那个xib。
    2. 设置从xib到班级的出口。
    3. 我尝试在主窗口中使用此自定义视图,执行以下步骤:

      1. 将自定义视图拖到主窗口的xib。
      2. 将该自定义视图的类设置为上面创建的类。
      3. 但没有渲染。从日志中,我可以看到自定义视图类中awakeFromNib中的代码已执行。当我将类设置为IB_DESIGNABLE时,视图在主窗口的xib中变空,与我设计的不同。

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

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

        更新:

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

        @property (nonatomic, strong) IBOutlet NSView *view;
        

        ,然后将其加载到(id)initWithCoder:(NSCoder *)coder方法中。

        [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self topLevelObjects:nil];
        [self addSubview:self.view];
        

        但是视图仍然无法在界面构建器中呈现。

2 个答案:

答案 0 :(得分:3)

您的猜测是正确的:未加载xib。 nib加载器不了解您的自定义视图的笔尖。 nib框架没有提供定义该连接的工具,因此您需要编写代码来加载xib。

这就是我的所作所为。在自定义视图中添加contentView属性:

@interface MyView ()

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

@end

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

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

@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

请注意,必须注意不要允许无限递归。当您的应用加载主窗口的笔尖时,它将创建MyView的实例并(最终)发送它awakeFromNib。然后,在awakeFromNib中,MyView加载自己的笔尖,即文件所有者。 nib加载程序将awakeFromNib发送给文件所有者,当您已经在-[MyView awakeFromNib]时,就会发生这种情况。如果你不检查这个,由于无限递归,你会得到堆栈溢出。

答案 1 :(得分:2)

您没有提供任何代码,但这里有一些完整性检查:

  • 您是否正确指定了笔尖名称?在iOS中,它的上限很敏感,但我不认为它适合你。

  • 检查包裹,实际上是否有笔尖?确保它是您正在构建的目标的一部分。

  • 也可能是一个框架问题。确保您的自动调整大小参数设置正确并且所有内容都在框架内。

  • 您可以做的另一项检查是将您的IBOutlets设置为您感兴趣的UIView(或其他)的实际帧。然后在awakeFromNib中,您可以确保它们的框架存在,或者它们是否存在