2012-07-08 35 views
3

我正在使用NSCollectionView來顯示各種對象。整個事情工作得很好,除了一件煩人的事情。我無法弄清楚如何訪問用於表示集合中每個對象的視圖上的各種控件。訪問NSCollectionView的視圖控件

這裏的設置:

  • 我已經拖了NSCollectionView到我在IB視圖。
  • 我做了一個NSCollectionViewItem的自定義子類。在IB中映射我的課程。
  • 我做了NSBox的自定義子類作爲集合中每個對象的視圖。也在IB中映射此類並將其連接到我的NSCollectionViewItem子類的view屬性。
  • 我讓IB中的所有綁定都顯示每個對象的正確信息。

的視圖:

enter image description here

所得集合視圖:

enter image description here

推理我的NSCollectionViewItem子類基本上是爲集合中的每個視圖的控制器,我在控制器子類中引用了視圖中各個控件的插口:

@interface SourceCollectionViewItem : NSCollectionViewItem 

@property (weak) IBOutlet NSTextField *nameTextField; 
@property (weak) IBOutlet NSTextField *typeTextField; 
@property (weak) IBOutlet RSLabelView *labelView; 
@property (weak) IBOutlet NSButton *viewButton; 

@end 

當我在調試器檢查的SourceCollectionViewItem任何情況下,所有屬性顯示爲無盡管事實上,我可以清楚地看到他們我的屏幕上顯示,一切都理所應當的。

我的設置受到蘋果示例應用程序IconCollection的啓發。

我明顯錯過了一些東西。什麼?

編輯:我發現各種帖子暗示在類似的問題: CocoaBuilder.comthis question SO。

編輯:只是要完成:this post處理該主題,並提供了一個解決方案基於接受答案中提到的選項的組合。

+0

第二次編輯中的鏈接被打破。但是我通過[WayBack Machine]找到博客文章(https://web.archive.org/web/20120124050817/http://benedictcohen.co.uk/blog/archives/72) – 2014-08-19 22:33:26

回答

6

在筆尖加載期間設置出口,並且只有原型項目從筆尖加載並且分配了其出口。所有其他的ViewItem和它們的View都是從原型中克隆出來的,在這種情況下,插座只是實例變量,它們從不初始化。

這裏是我能想出的選項:

  • 覆蓋集合視圖和重裝筆尖,而不是克隆原型newItemForRepresentedObject:。但這可能會大大地損害性能。
  • 覆蓋收集查看項目的copyWithZone並使用viewWithTag:手動分配網點以查找它們。
  • 放棄並嘗試僅通過綁定提供數據。
1

我發現,覆蓋NSCollectionViewItem的-setRepresentedObject:也可能是一個不錯的選擇,因爲它是所謂的新項目時,所有IBOutlet中似乎是準備好了。調用super後,你可以做任何需要:

- (void)setRepresentedObject:(id)representedObject 
{ 
    if (representedObject) { 
     [super setRepresentedObject:representedObject]; 
     [self.anOutlet bind:@"property" toObject:self.representedObject withKeyPath:@"representeProperty" options:nil]; 
    } 
} 

我用這個方法的接口對象的自定義屬性綁定。當代表對象尚未準備就緒時,該檢查可以避免無用的調用。該項目爲ViewItem使用單獨的xib,如原始編輯中的鏈接所述。

0

偉大的問題。就像@hamstergene建議的那樣,您可以使用copyWithZone,與newItemForRepresentedObject相比,它會更加高效。然而,viewWithTag並不總是一種選擇,首先,因爲並非所有東西都可以被標記(很容易),其次,爲此目的使用標籤有點不對。在Swift中,這是一個很酷的方法,考慮到性能。

import AppKit 

class MyViewController: NSCollectionItemView 
{ 

    // Here you are cloning the original item loaded from the storyboard, which has 
    // outlets available, but as you've seen the default implementation doesn't take 
    // care of them. Each view has a unique identifiers, which you can use to find it 
    // in sublayers. What's really cool about this, is that you don't need to assign 
    // any tags or do anything else while having advantage of better performance using 
    // cached nib object. 

    override func copyWithZone(zone: NSZone) -> AnyObject { 
     let copy: NSCollectionItemView = super.copyWithZone(zone) as! NSCollectionItemView 
     let oldView: RecordingView = self.view as! MyView 
     let newView: RecordingView = copy.view as! MyView 

     newView.foo = newView.viewWithIdentifier(oldView.foo.identifier!) as! NSTextfield 
     newView.bar = newView.viewWithIdentifier(oldView.bar.identifier!) as! NSImageView 

     return copy 
    } 
} 

@IBDesignable class MyView: View 
{ 

    // Custom collection view item view. Lets assume inside of it you have two subviews which you want 
    // to access in your code. 

    @IBOutlet weak var foo: NSTextfield! 
    @IBOutlet weak var bar: NSImageView! 
} 

extension NSView 
{ 

    // Similar to viewWithTag, finds views with the given identifier. 

    func viewWithIdentifier(identifier: String) -> NSView? { 
     for subview in self.subviews { 
      if subview.identifier == identifier { 
       return subview 
      } else if subview.subviews.count > 0, let subview: NSView = subview.viewWithIdentifier(identifier) { 
       return subview 
      } 
     } 
     return nil 
    } 
}