Cocoa 将阵列控制器初始化从nib移动到代码会中断表视图绑定 我的窗口控制器子类是nib的所有者 我在我的文档子类中用代码实例化我的数组控制器。文档和窗口控制器都在代码中使用它 我像这样绑定表列:文件所有者>>文档。\u arrayController.arrangedObjects.attributeName 表视图不显示任何行 窗口控制器和文档类都不会接收与表视图相关的-addObserver消息

Cocoa 将阵列控制器初始化从nib移动到代码会中断表视图绑定 我的窗口控制器子类是nib的所有者 我在我的文档子类中用代码实例化我的数组控制器。文档和窗口控制器都在代码中使用它 我像这样绑定表列:文件所有者>>文档。\u arrayController.arrangedObjects.attributeName 表视图不显示任何行 窗口控制器和文档类都不会接收与表视图相关的-addObserver消息,cocoa,nstableview,cocoa-bindings,nsarraycontroller,nswindowcontroller,Cocoa,Nstableview,Cocoa Bindings,Nsarraycontroller,Nswindowcontroller,显然,我没有正确绑定到此阵列控制器。我想我缺少了一些关于表视图列如何绑定到数组的基本知识 这个问题是在重构过程中出现的。我曾经在nib中实例化数组控制器。该文档是文件所有者,并且有一个用于阵列控制器的出口。绑定看起来像My Array Controller>arrangedObjects>attributeName。一切都很顺利 由于文档处理通过数组控制器插入对象的操作,我认为窗口控制器不应该负责创建它。窗口控制器是新的nib所有者,因此我将其从nib中删除。我现在在-makeWindowCon

显然,我没有正确绑定到此阵列控制器。我想我缺少了一些关于表视图列如何绑定到数组的基本知识

这个问题是在重构过程中出现的。我曾经在nib中实例化数组控制器。该文档是文件所有者,并且有一个用于阵列控制器的出口。绑定看起来像My Array Controller>arrangedObjects>attributeName。一切都很顺利

由于文档处理通过数组控制器插入对象的操作,我认为窗口控制器不应该负责创建它。窗口控制器是新的nib所有者,因此我将其从nib中删除。我现在在
-makeWindowController
中的代码中创建它。(我问了这个。)

在调试这个时,我发现了一些其他的东西。如果窗口控制器是表视图的数据源,并且我实现了
-numberOfRowsInDataSource

return [[self.document._arrayController arrangedObjects] count];
表视图调用它,为所有列发送
-addObserver
消息,并实际使用绑定为每个单元格加载值。但是,当加载给定单元格的值时,它不会加载
arrangedObjects
中第n个对象的属性值,而是加载整列对象的属性值。它将这些数组传递给值转换器(无法正确处理它们),并在文本单元格中显示数组的
说明
(它们不适合)

当窗口控制器是表视图的数据源但列使用绑定时,表视图应该忽略
-numberOfRowsInTableView
的结果,或者根本不应该调用它。(使用
return0
响应选择器只会避免运行时错误。数据源只在第一时间设置为实现单元格的工具提示。)同样,当我在nib中创建阵列控制器时,所有这些都可以正常工作

一些想法:

  • 甚至可以使用IB将表列绑定到另一个对象所拥有的数组控制器吗
  • 我是否需要将数组控制器放回nib,并让窗口控制器与文档实例共享它?(这听起来像是可怕的设计。)
  • 我应该有两个数组控制器,一个用于窗口控制器,另一个用于文档

  • 添加:

    我使用表视图数据源和绑定的原因是使用以下方法实现拖放重新排序:

    • tableView:writeRowsWithIndexes:toPasteboard:
    • tableView:validateDrop:proposedRow:proposedDropOperation:
    • tableView:acceptDrop:row:dropOperation:
      • 一些想法:

        首先,您不应该同时实现NSTableViewDataSource协议和使用绑定——这通常是其中之一。如果您有这样做的特定原因,我会首先使用绑定启动并运行您的应用程序,然后一步一步地从NSTableViewDataSource中插入您想要的任何功能,以确保一切正常。有可用于支持工具提示的绑定

        接下来,我不是说这是唯一的方法,而是建议将ArrayController放回xib。NSController子类和绑定到它们的控件之间似乎有一种特殊的关系——绑定检查器中的Controller Key:entry强烈地暗示了这一点,因为当您不使用它时,它被禁用。我不确定,但我猜,当您通过那个大的键路径绑定到文档以获取arrayController时,这种魔法不会发生

        我还想知道为什么您希望NSArrayController位于控件绑定到它的窗口之外的其他位置?与此相关的是,为什么要让WindowController与文档共享NSArrayController

        NSArrayController保持选择状态,因此每个窗口都有一个选择状态是有意义的,或者更抽象地说,它们将位于UI附近,因此应该存在于每个需要选择状态的nib中。也就是说,除非您尝试执行一些非常规操作,例如在多个窗口之间共享单个选择状态(即,更改窗口a中的选择,并且窗口B中的相应控件也会更改选择以匹配窗口a)。我将在下面探讨这一点,但简而言之,我想不出还有什么其他原因可以让您共享一个arrayController,而不是让多个arrayController绑定到同一基础数据

        如果选择共享是您的目标,我认为您最好做一些事情,比如让文档在每个窗口中的nib创建的ArrayController的SelectionIndex上设置键值观察,并让它们将选择传播到其他窗口的ArrayController

        我把它编好了;它似乎起作用了。我从Xcode中基于NSDocument的标准Cocoa应用程序模板开始,在文档中添加了一个
        dataModel
        属性,并用一些数据伪造了它。然后,我在
        makeWindowController
        期间创建了两个窗口,然后添加了观测值等,以使它们的选择相互遵循。一切似乎都很顺利

        压缩成一个代码块:

        #import <Cocoa/Cocoa.h>
        
        @interface SODocument : NSDocument
        @property (retain) id dataModel;
        @end
        
        @interface SOWindowController : NSWindowController
        @property (retain) IBOutlet NSArrayController* arrayController;
        @end
        
        @implementation SODocument
        @synthesize dataModel = _dataModel;
        
        - (id)init
        {
            self = [super init];
            if (self) 
            {
                // Make some fake data to bind to
                NSMutableDictionary* item1 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 1", @"attributeName", nil];
                NSMutableDictionary* item2 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 2", @"attributeName", nil];
                NSMutableDictionary* item3 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 3", @"attributeName", nil];        
                _dataModel = [[NSMutableArray arrayWithObjects: item1, item2, item3, nil] retain];
            }
            return self;
        }
        
        - (void)dealloc
        {
            [_dataModel release];
            [super dealloc];
        }
        
        - (NSString *)windowNibName
        {
            return @"SODocument";
        }
        
        - (void)makeWindowControllers
        {
            SOWindowController* wc1 = [[[SOWindowController alloc] initWithWindowNibName: [self windowNibName]] autorelease];
            [self addWindowController: wc1];
        
            SOWindowController* wc2 = [[[SOWindowController alloc] initWithWindowNibName: [self windowNibName]] autorelease];
            [self addWindowController: wc2];
        }
        
        - (void)addWindowController:(NSWindowController *)windowController
        {
            [super addWindowController: windowController];
            [windowController addObserver:self forKeyPath: @"arrayController.selectionIndexes" options: 0 context: [SODocument class]];
        }
        
        - (void)removeWindowController:(NSWindowController *)windowController
        {
            [windowController removeObserver:self forKeyPath: @"arrayController.selectionIndexes" context: [SODocument class]];
            [super removeWindowController:windowController];
        }
        
        -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
        {
            if ([SODocument class] == context && [@"arrayController.selectionIndexes" isEqualToString: keyPath])
            {
                NSIndexSet* selectionIndexes = ((SOWindowController*)object).arrayController.selectionIndexes;
                for (SOWindowController* wc in self.windowControllers)
                {
                    if (![selectionIndexes isEqualToIndexSet: wc.arrayController.selectionIndexes])
                    {
                        wc.arrayController.selectionIndexes = selectionIndexes;
                    }
                }
            }
        }
        @end
        
        @implementation SOWindowController
        @synthesize arrayController = _arrayController;
        
        -(void)dealloc
        {
            [_arrayController release];
            [super dealloc];
        }
        @end
        
        #导入
        @接口文档:NSDocument
        @财产