以编程方式从nib的NSView子类加载对象

nac*_*o4d 18 macos cocoa objective-c

如何使用Xib正确加载作为NSView子类的对象?

我希望它不是从头开始动态加载,所以我做了一个MyView.Xib来自MyDocument.m我做了:

MyView *myView = [[MyView alloc] initWithFrame:...];
[NSBundle loadNibNamed:@"MyView" owner:myView];
[someview addSubview:myView];
...
Run Code Online (Sandbox Code Playgroud)

并且背景很好(它调用drawrect:它按预期绘制)但是我放在xib上的所有按钮都不会出现.我已经检查了,他们已经加载但他们的超级视图不是同一个对象myView.

为什么是这样?我想我在Xib中遗漏了一些东西,但我不知道究竟是什么.换句话说:我如何确保我的xib中的根视图与文件所有者是同一个对象?

我希望mac有类似的东西:

NSArray* nibViews =  [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil]; //in iOS this will load the xib
MyView* myView = [ nibViews objectAtIndex:1];
[someview addSubview:myView];
...
Run Code Online (Sandbox Code Playgroud)

提前致谢.

编辑

我想我已经意识到问题的根源......(??)

在MyView类中,我有各种IBOutlet,它们在IB中正确连接,这就是为什么它们加载得很好(我可以参考它们).但是顶视图没有IBOutlet.因此,当NSBundle加载nib时,顶视图会被分配给其他对象.我认为如果我将IB中的顶视图设置为来自类:MyView并且将其myView作为所有者,[NSBundle loadNibNamed:@"MyView" owner:myView];但似乎并非如此.我究竟做错了什么?

小智 31

请注意,nib文件包含:

  • 一个或多个顶级对象.例如,一个实例MyView;
  • 文件的所有者占位符.这是在加载nib文件之前存在的对象.由于它在加载nib文件之前存在,因此它不能与nib文件中的视图相同.

场景1: NSNib

让我们考虑你的nib文件只有一个顶级对象,其类是MyView,文件的所有者类是MyAppDelegate.在这种情况下,考虑到nib文件是在以下实例方法中加载的MyAppDelegate:

NSNib *nib = [[[NSNib alloc] initWithNibNamed:@"MyView" bundle:nil] autorelease];
NSArray *topLevelObjects;
if (! [nib instantiateWithOwner:self topLevelObjects:&topLevelObjects]) // error

MyView *myView = nil;
for (id topLevelObject in topLevelObjects) {
    if ([topLevelObject isKindOfClass:[MyView class]) {
        myView = topLevelObject;
        break;
    }
}

// At this point myView is either nil or points to an instance
// of MyView that is owned by this code
Run Code Online (Sandbox Code Playgroud)

它看起来像第一个参数-[NSNib instantiateNibWithOwner:topLevelObjects:]可以nil这样你不必指定一个所有者,因为它似乎你没有兴趣有一个:

if (! [nib instantiateWithOwner:nil topLevelObjects:&topLevelObjects]) // error
Run Code Online (Sandbox Code Playgroud)

虽然这有效,但我不会依赖它,因为它没有记录.

请注意,您拥有顶级对象的所有权,因此您有责任在不再需要它们时释放它们.

场景2: NSViewController

Cocoa提供NSViewController管理视图; 通常,从nib文件加载的视图.您应该创建一个NSViewController包含所需出口的子类.编辑nib文件时,请设置view插座以及您可能已定义的其他插座.您还应该设置nib文件的所有者,以便它的类是它的子类NSViewController.然后:

MyViewController *myViewController = [[MyViewController alloc] initWithNibName:@"MyView" bundle:nil];
Run Code Online (Sandbox Code Playgroud)

NSViewController发送时自动加载nib文件并设置相应的插座-view.或者,您可以强制它通过发送加载nib文件-loadView.


Pet*_*isu 6

您可以参考此类别

https://github.com/peterpaulis/NSView-NibLoading-/tree/master

+ (NSView *)loadWithNibNamed:(NSString *)nibNamed owner:(id)owner class:(Class)loadClass {

    NSNib * nib = [[NSNib alloc] initWithNibNamed:nibNamed bundle:nil];

    NSArray * objects;
    if (![nib instantiateWithOwner:owner topLevelObjects:&objects]) {
        NSLog(@"Couldn't load nib named %@", nibNamed);
        return nil;
    }

    for (id object in objects) {
        if ([object isKindOfClass:loadClass]) {
            return object;
        }
    }
    return nil;
}
Run Code Online (Sandbox Code Playgroud)