3

我正在使用一个NSCollectionView来显示各种对象。整个事情都很好,除了一件烦人的事情。我无法弄清楚如何访问用于表示集合中每个对象的视图上的各种控件。

这是设置:

  • NSCollectionView我在 IB中拖入了我的视图。
  • 我做了一个自定义子类NSCollectionViewItem。映射我在 IB 中的课程。
  • 我创建了一个自定义子类NSBox来充当集合中每个对象的视图。还在 IB 中映射了此类并将其连接到view我的NSCollectionViewItem子类的属性。
  • 我在 IB 中进行了所有绑定以显示每个对象的正确信息。

风景:

在此处输入图像描述

生成的集合视图:

在此处输入图像描述

推理我的子类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,所有属性都显示为 nil,尽管我实际上可以在屏幕上看到它们并且所有内容都按应有的方式显示。

我的设置灵感来自 Apple 的示例应用IconCollection

我显然错过了一些东西。什么?

编辑:我发现各种帖子都暗示了一个类似的问题: CocoaBuilder.com这个关于 SO 的问题。

编辑:为了完整起见:这篇文章也涉及该主题,并根据已接受答案中提到的选项的组合提供解决方案。

4

3 回答 3

6

在 nib 加载期间设置出口,只有原型项目从 nib 加载并分配其出口。所有其他ViewItems 和它们View的 s 都是从原型中克隆的,在这种情况下,出口只是从未初始化的实例变量。

以下是我能想到的选项:

  • 覆盖newItemForRepresentedObject:集合视图并重新加载 nib 而不是克隆原型。但这可能会极大地损害性能。
  • 覆盖copyWithZone集合视图项目并手动分配网点 viewWithTag:以查找它们。
  • 放弃并尝试仅通过绑定提供数据。
于 2012-07-09T07:45:35.557 回答
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,如原始编辑中的链接中所述。

于 2014-08-31T22:14:39.163 回答
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
    }
}
于 2016-02-04T19:35:46.573 回答