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

Objective c 在其他视图中调用时,使用Interface Builder创建的自定义视图不会呈现,objective-c,xcode,interface-builder,Objective C,Xcode,Interface Builder,我有一个主窗口的xib,我通过以下步骤创建了一个自定义视图: 创建从NSView继承的新类 MyView.h: #import <Cocoa/Cocoa.h> IB_DESIGNABLE @interface MyView : NSTableCellView @end 创建一个新的xib,并将根视图的类设置为上面创建的类。并在该xib中进行设计 设置从xib到课堂的插座 我尝试在主窗口中按以下步骤使用此自定义视图: 将自定义视图拖动到主窗口的xib

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

  • 创建从
    NSView
    继承的新类
  • MyView.h

        #import <Cocoa/Cocoa.h>
        IB_DESIGNABLE
        @interface MyView : NSTableCellView
        @end
    
  • 创建一个新的xib,并将根视图的类设置为上面创建的类。并在该xib中进行设计
  • 设置从xib到课堂的插座
  • 我尝试在主窗口中按以下步骤使用此自定义视图:

  • 将自定义视图拖动到主窗口的xib
  • 将该自定义视图的类设置为上面创建的类
  • 但什么也没有。从日志中,我可以看到自定义视图类中的
    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];
    

    但是该视图仍然不会在界面生成器中呈现。

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

    • 您是否正确指定了nib名称?在iOS中,它的帽子很敏感,但我认为它不适合你

    • 检查一下包装,笔尖真的在吗?确保它是您正在构建的目标的一部分

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

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


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

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

    @interface MyView ()
    
    @property (nonatomic, strong, readwrite) IBOutlet NSView *contentView;
    
    @end
    
    在自定义视图的nib中,将根视图的自定义类设置回
    NSView
    ,并断开所有(不再有效)的插座连接。将文件所有者的自定义类设置为自定义类名(例如,
    MyView
    )。将根视图连接到文件所有者的
    contentView
    outlet,并将文件所有者的所有其他outlet连接到nib中的相应对象

    然后在自定义视图子类中实现
    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
    

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

    只是一个小注释:您的IBOutlets(除非在特殊情况下)应该始终很弱。原因是该引用属于nib加载程序。此外,您并不是在“创建从NSView继承的新类”,实际上,它是从NSTableCellView继承的。现在还不知道NSTableCellView在做什么,所以也许您现在可以将代码简化为NSView?在iOS loadNibNamed中,要看的另一件事是:实际返回一个视图数组,而不是实际的视图。所以,请检查退货。NSArray*视图=[[NSBundle mainBundle]loadNibNamed:@“MyView”所有者:self-topLevelObjects:nil];MyView*MyView=视图[0];
    @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