Несколько мыслей:
Во-первых, вы не должны реализовывать оба протокола NSTableViewDataSource и использовать привязки - обычно это одно или другое. Если у вас есть конкретная причина для этого, я бы сначала запустил ваше приложение, используя только привязки, а затем добавлял все необходимые функции из NSTableViewDataSource по одному шагу за раз, чтобы убедиться, что все работает. Для поддержки всплывающих подсказок доступны привязки.
Далее, я не говорю, что это единственный подход, но я бы предложил вернуть ArrayController обратно в xib. Кажется, между подклассами NSController и связанными с ними элементами управления существует особая связь - ключ контроллера: запись в инспекторе привязок намекает на это, поскольку она отключена, когда вы ее не используете. Я не знаю наверняка, но я предполагаю, что когда вы связываете этот большой keyPath, чтобы вернуться к документу, чтобы получить arrayController, это волшебство не происходит.
Мне также интересно, почему вы хотите, чтобы NSArrayController жил в другом месте, кроме окна, чьи элементы управления привязаны к нему? И в связи с этим, почему у вас есть WindowController общий доступ NSArrayController с документом?
NSArrayControllers хранят состояние выбора, поэтому действительно имеет смысл, что они будут по одному на окно или более абстрактно, что они будут жить близко к пользовательскому интерфейсу и, следовательно, должны существовать в каждом перо, которое нуждается в нем. То есть, если вы не пытаетесь сделать что-то необычное, например разделить одно состояние выбора между несколькими окнами (то есть изменить выбор в окне A, а соответствующие элементы управления в окне B также изменить выбор в соответствии с окном A). Я расскажу об этом ниже, но вкратце, я не могу думать о какой-либо другой причине, по которой вы захотите использовать arrayController, если несколько arrayController связаны с одними и теми же базовыми данными.
Если бы вашей целью было совместное использование выборки, я думаю, что вам было бы лучше сделать что-то вроде установки в документе значений ключа-значения в selectionIndexes ArrayControllers, созданных с помощью пера в каждом окне, и попросить их распространить выборку на Контроллеры массива других окон.
Я закодировал это; Похоже на работу. Я начал со стандартного шаблона приложения Какао на основе NSDocument в XCode, добавил в документ свойство dataModel
и подделал его с некоторыми данными. Затем я сделал два окна во время makeWindowControllers
, затем добавил наблюдения и т. Д., Чтобы их выбор следовал друг за другом. Казалось, все хорошо сошлось.
В одном кодовом блоке:
#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
Перо документа имеет владельца файла SOWindowController. Он имеет NSArrayController, привязанный к File's Owner.document.dataModel
, и NSTableView с одним столбцом, привязанным к ArrayController.arrangedObjects.attributeName
.
При создании нового документа появляются два окна, каждое из которых показывает одно и то же. Когда я изменяю выбор tableView в одном, другой изменяется также.
В любом случае, надеюсь, это поможет.