いくつかの考え:
まず、NSTableViewDataSourceプロトコルとバインディングの両方を実装するべきではありません。通常はどちらか一方です。これを行う特別な理由がある場合は、最初にバインディングのみを使用してアプリを稼働させ、次にNSTableViewDataSourceから必要な機能を1ステップずつレイヤー化して、すべてが機能していることを確認します。ツールチップをサポートするために使用できるバインディングがあります。
次に、これが唯一のアプローチであるとは言いませんが、ArrayControllerをxibに戻すことをお勧めします。NSControllerサブクラスとそれらにバインドするコントロールの間には特別な関係があるようです-コントローラーキー:バインディングインスペクターのエントリは、使用していないときは無効になっているため、これを強く示唆しています。確かなことはわかりませんが、その大きなkeyPathをバインドしてドキュメントに戻り、arrayControllerを取得しても、その魔法は発生していないと思います。
また、NSArrayControllerを、コントロールがバインドされているウィンドウ以外の場所に配置する必要があるのはなぜでしょうか。また、それに関連して、WindowControllerがNSArrayControllerをドキュメントと共有するのはなぜですか?
NSArrayControllersは選択状態を保持するため、ウィンドウごとに1つ、またはより抽象的にはUIの近くに存在するため、1つを必要とする各ペン先に存在する必要があります。つまり、複数のウィンドウ間で単一の選択状態を共有するなど、型にはまらないことをしようとしている場合を除きます(つまり、ウィンドウAの選択を変更し、ウィンドウBの対応するコントロールもウィンドウAに一致するように選択を変更します)。これについては以下で説明しますが、要するに、同じ基になるデータに複数のarrayControllerをバインドするよりも、arrayControllerを共有したい他の理由は考えられません。
選択の共有が目標である場合は、ドキュメントで各ウィンドウのnibで作成されたArrayControllerのselectionIndexesにKey-Value Observancesを設定し、選択を他のウィンドウに伝播させるようなことを行う方がよいと思います。 'arrayControllers。
私はこれをコーディングしました。動作しているようです。Xcodeの標準のNSDocumentベースのCocoaアプリテンプレートから始めてdataModel
、ドキュメントにプロパティを追加し、いくつかのデータで偽造しました。次に、の間に2つのウィンドウを作成しmakeWindowControllers
、次に、それらの選択が互いに続くように、遵守事項などを追加しました。すべてがうまくまとまっているようでした。
1つのコードブロックに押しつぶされます:
#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
ドキュメントnibには、SOWindowControllerのファイル所有者がいます。にバインドされFile's Owner.document.dataModel
たNSArrayControllerと、にバインドされた1つの列を持つNSTableViewがありますArrayController.arrangedObjects.attributeName
。
新しいドキュメントを作成すると、2つのウィンドウが表示され、それぞれに同じものが表示されます。一方のtableView選択を変更すると、もう一方も変更されます。
とにかく、これが役立つことを願っています。