2011-05-02 56 views
17

如何正确加载使用Xib的NSView的子类的对象?以编程方式从nib的NSView的子类加载对象

我想它从一开始就被加载动态不那么我做了一个MyView.Xib 从MyDocument.m我所做的:

MyView *myView = [[MyView alloc] initWithFrame:...]; 
[NSBundle loadNibNamed:@"MyView" owner:myView]; 
[someview addSubview:myView]; 
... 

和背景是好的(它调用的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]; 
... 

在此先感谢。

编辑

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

在MyView的类我有在IB,这就是为什么他们加载正确连接各种IBOutlet中很好(我可以参考他们)。但是顶视图没有IBOutlet。所以当NSBundle加载笔尖时,顶视图会被分配给其他一些对象。我认为这会发生,如果我把我在IB的顶视图从类:MyView,并把myView作为所有者[NSBundle loadNibNamed:@"MyView" owner:myView];,但似乎并非如此。 我在做什么错?

+0

尝试将它们移动到前面也许它将它画在背面并且不能被看到因为背景 – Radu 2011-05-02 08:53:44

+0

我刚刚尝试过......这是没有发生;( – nacho4d 2011-05-02 09:00:43

+0

在你的nib文件中,是否有顶级视图,其类是“MyView”?nib文件中是否还有其他顶级对象?文件所有者的类是什么? – 2011-05-02 09:18:52

回答

28

注意,笔尖文件包含:

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

方案1:NSNib

让我们考虑你的笔尖文件只有一个顶级对象,它的类MyView,而文件的所有者类是MyAppDelegate。在这种情况下,考虑到笔尖文件中的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 

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

if (! [nib instantiateWithOwner:nil topLevelObjects:&topLevelObjects]) // error 

虽然这个工程,我不会依赖它,因为它没有记录。

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

方案2:NSViewController

可可提供NSViewController管理视图;通常,从nib文件加载的视图。您应该创建一个NSViewController的子类,其中包含需要的任何插座。编辑笔尖文件时,请设置view插座和您可能定义的其他插座。您还应该设置nib文件的所有者,以便其类是NSViewController的这个子类。然后:

MyViewController *myViewController = [[MyViewController alloc] initWithNibName:@"MyView" bundle:nil]; 

NSViewController自动加载的笔尖文件,并设置相应的网点,当你把它-view。或者,您可以强制它通过发送它加载nib文件-loadView

+0

我的笔尖只有一个顶级对象,其类是“MyView”,但是文件所有者也是“MyView”,这是可能的吗? – nacho4d 2011-05-02 09:54:29

+0

如果你有另外一个'MyView'实例在nib文件被加载之前就已经创建了,注意这意味着这个实例已经被创建编程或从另一个nib文件加载,不同于MyView.nib。 – 2011-05-02 09:57:56

+0

我有MyView * myView实例,它已经使用[[MyView alloc] initWithFrame创建:];我在[NSBundle loadNib:@“MyView”owner: myView];我仍然不明白为什么这不起作用;( – nacho4d 2011-05-02 10:11:52

5

您可以参考这一类

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; 
} 
1

我通过@Bavarious非常有用找到了答案,但它仍然需要对我而言有些squirrelling,使之成为我的使用情况下工作 - 将几个xib的视图定义中的一个加载到现有的“容器”视图中。这是我的工作流程:

1)在.xib中,按预期在IB中创建视图。

2)不要添加对象的新观点的的viewController,而是

3)设置的.xib的文件的所有者,以新的观点的的viewController

4)连接的任何网点&行动,以文件的所有者,并且具体地,.view

5)调用loadInspector(见下文)。

enum InspectorType { 
    case None, ItemEditor, HTMLEditor 

    var vc: NSViewController? { 
     switch self { 
     case .ItemEditor: 
      return ItemEditorViewController(nibName: "ItemEditor", bundle: nil) 
     case .HTMLEditor: 
      return HTMLEditorViewController(nibName: "HTMLEditor", bundle: nil) 
     case .None: 
      return nil 
     } 
    } 
} 

class InspectorContainerView: NSView { 

    func loadInspector(inspector: InspectorType) -> NSViewController? { 
     self.subviews = [] // Get rid of existing subviews. 
     if let vc = inspector.vc { 
      vc.loadView() 
      self.addSubview(vc.view) 
      return vc 
     } 
     Swift.print("VC NOT loaded from \(inspector)") 
     return nil 
    } 
} 
0
class CustomView: NSView { 

@IBOutlet weak var view: NSView! 
@IBOutlet weak var textField: NSTextField! 

required init(coder: NSCoder) { 
    super.init(coder: coder)! 

    let frameworkBundle = Bundle(for: classForCoder) 
    assert(frameworkBundle.loadNibNamed("CustomView", owner: self, topLevelObjects: nil)) 
    addSubview(view) 
} 

}

0

这里是写的NSView子类,所以认为自己从一个单独的厦门国际银行将完全和拥有一切设置正确的方式。它依赖于init可以更改self的值的事实。

使用Xcode创建一个新的'视图'xib。将文件所有者的类设置为NSViewController,并将它的view出口设置为您的目标视图。将目标视图的类设置为您的NSView子类。布局视图,连接插座等,现在

,在你的NSView子类,实现指定的初始化:

- (id)initWithFrame:(NSRect)frameRect 
{ 
    NSViewController *viewController = [[NSViewController alloc] init]; 
    [[NSBundle mainBundle] loadNibNamed:@"TheNib" owner:viewController topLevelObjects:NULL]; 

    id viewFromXib = viewController.view; 
    viewFromXib.frame = frameRect; 
    self = viewFromXib; 
    return self; 
} 

并与initWithCoder:因此,它也将在另一个使用的NSView子类时的工作方式相同厦门国际银行。

相关问题