objective-c - 在其他 View 中调用时,使用 Interface Builder 创建的自定义 View 不会呈现

标签 objective-c xcode interface-builder

我有一个用于主窗口的 xib,我按照以下步骤创建了一个自定义 View :

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

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,并将 Root View 的类设置为上面创建的类。并在那个 xib 中进行设计。
  2. 设置从 xib 到类的导出。

我尝试按照以下步骤在主窗口中使用此自定义 View :

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

但没有渲染。从日志中,我可以看到执行了自定义 View 类中的 awakeFromNib 中的代码。当我将类设置为 IB_DESIGNABLE 时,主窗口的 xib 中的 View 变为空,与我设计的不同。

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

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

更新:

我找到了一个教程并意识到我缺少什么(构建时正确渲染 View )。我必须从 xib 中的 View 向 View 类添加一个导出:

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

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

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

但是 View 仍然不会在界面构建器中呈现。

最佳答案

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

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

@interface MyView ()

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

@end

在自定义 View 的 nib 中,将 Root View 的自定义类设置回 NSView 并断开所有(不再有效的)导出连接。将文件所有者的自定义类设置为您的自定义类名(例如 MyView)。将 Root View 连接到 File's Owner 的 contentView 导出,并将 File's Owner 的所有其他导出连接到 nib 中的适当对象。

然后在您的自定义 View 子类中实现 awakeFromNib 以加载 nib 并将内容 View 添加为 subview :

@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 实例并(最终)将其发送给 awakeFromNib。然后,在 awakeFromNib 中,MyView 加载它自己的 nib,它是文件所有者。 nib 加载程序将 awakeFromNib 发送给文件所有者,这将在您已经在 -[MyView awakeFromNib] 中时发生。如果您不对此进行检查,则会由于无限递归而导致堆栈溢出。

关于objective-c - 在其他 View 中调用时,使用 Interface Builder 创建的自定义 View 不会呈现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33329280/

相关文章:

objective-c - iOS:从另一个文件导入调用的问题

ios - 无法实例化函数 无法转换类型为 '__NSArrayI' 的值

iphone - 初学者 iPhone 开发问题

ios - 通过 ibtool 生成字符串时如何使 UILabel 内容不可本地化?

objective-c - 如何链接 Interface Builder View

ios - 通知警报不起作用

c# - 从另一个类调用委托(delegate)方法

ios - 从文档目录获取文件路径 - Objective-c iOS

ios - 错误 : Build input file cannot be found: '/Users/GoogleService-Info.plist' (in target 'Runner' from project 'Runner' )

ios - 使用 Cocoapods 添加 Firebase 时的 Apple Mach-O 链接器错误组