SidebarDemoサンプルコードは、同じオブジェクトを使用してアウトラインビューの複数の行を表すという間違いを犯します。特に、データソースで使用される基になるデータは次のように作成されます。
_childrenDictionary = [NSMutableDictionary new];
[_childrenDictionary setObject:[NSArray arrayWithObjects:@"ContentView1", @"ContentView2", @"ContentView3", nil] forKey:@"Favorites"];
[_childrenDictionary setObject:[NSArray arrayWithObjects:@"ContentView1", @"ContentView2", @"ContentView3", nil] forKey:@"Content Views"];
[_childrenDictionary setObject:[NSArray arrayWithObjects:@"ContentView2", nil] forKey:@"Mailboxes"];
[_childrenDictionary setObject:[NSArray arrayWithObjects:@"ContentView1", @"ContentView1", @"ContentView1", @"ContentView1", @"ContentView2", nil] forKey:@"A Fourth Group"];
同一の値のNSStringリテラルはコンパイラーによって一意であるため、出現するたび@"ContentView1"
にメモリー内の同じオブジェクトを参照します。この結果、内部のコードが-outlineView:viewForTableColumn:item:
アイテムの親を検索して、使用するアイコンまたは未読状態を決定すると、すべてのアイテム-[NSOutlineView parentForItem:]
に対して1つの親のみが返されます。@"ContentView1"
最初のケースでそれがまったく機能するという事実は、実装の偶然のようです。呼び出し-outlineView:viewForTableColumn:item:
が行われる順序は、初期ロード時とリロード時でわずかに異なります。
解決策は、一意のオブジェクトを使用して、アウトラインビューの各アイテムを表すことです。これを実現するSidebarDemoサンプルの最も簡単な変更は、各NSString値の可変コピーを作成してから次の場所に格納することです_childrenDictionary
。
_childrenDictionary = [NSMutableDictionary new];
[_childrenDictionary setObject:[NSArray arrayWithObjects:[@"ContentView1" mutableCopy], [@"ContentView2" mutableCopy], [@"ContentView3" mutableCopy], nil] forKey:@"Favorites"];
[_childrenDictionary setObject:[NSArray arrayWithObjects:[@"ContentView1" mutableCopy], [@"ContentView2" mutableCopy], [@"ContentView3" mutableCopy], nil] forKey:@"Content Views"];
[_childrenDictionary setObject:[NSArray arrayWithObjects:[@"ContentView2" mutableCopy], nil] forKey:@"Mailboxes"];
[_childrenDictionary setObject:[NSArray arrayWithObjects:[@"ContentView1" mutableCopy], [@"ContentView1" mutableCopy], [@"ContentView1" mutableCopy], [@"ContentView1" mutableCopy], [@"ContentView2" mutableCopy], nil] forKey:@"A Fourth Group"];
実際のコードでは、基になるデータオブジェクトが文字列リテラルだけで構成されるのではなく、モデルクラスのインスタンスで構成されるため、この問題に悩まされることはほとんどありません。