2011-05-02 41 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子類時的工作方式相同廈門國際銀行。

相關問題