2013-04-04 2 views
2

Я могу получить экземпляр NSBrowser для отображения правильных данных в первом столбце. Однако, когда я выбираю один из параметров, следующий столбец просто отображает один и тот же набор параметров. Я прочитал документы, посмотрел на соответствующий примерный пример кода Apple и почти все, что мог найти в Интернете, но я просто не могу понять правильный способ реализации необходимых методов. Данные, которые я предоставляю браузеру, представляют собой набор словарей. Каждый словарь, в свою очередь, содержит «детский» ключ, который является еще одним массивом словарей. И эти словари имеют свои собственные «ребенок» ключ, также являются массивами словарей и т.д. Использование JSON для описательных целей (объекты словарей, массивы массивы), это выглядит следующим образом:Проблемы с внедрением протокола NSBrowserDelegate

data = [ 
    { 
     name: 'David', 
     children:[ 
      { 
       name: 'Sarah', 
       children: {...} 
      }, 
      { 
       name: 'Kevin', 
       children: {...} 
      } 
     ] 
    }, 
    { 
     name: 'Mary', 
     children:[ 
      { 
       name: 'Greg', 
       children: {...} 
      }, 
      { 
       name: 'Jane', 
       children: {...} 
      } 
     ] 
    } 
] 

Так первая колонка должен показать «Дэвид» и «Мэри». Если выбран «Давид», следующий столбец должен показывать «Сара» и «Кевин» и т. Д.

Моя текущая реализация основана на пользовательском методе, который я создал, который должен переводить указательный путь браузера на соответствующий уровень NSArray из предоставленных данных. Этот метод выглядит следующим образом:

- (NSArray *)getSelectionInBrowser:(NSBrowser *)browser 
{ 
    NSArray *selection = browserData; 
    NSIndexPath *path = [browser selectionIndexPath]; 
    for (NSUInteger i = 0; i < path.length; i++) { 
     selection = [[selection objectAtIndex:i] objectForKey:@"children"]; 
    } 
    return selection; 
} 

Моя реализация требуемых методов NSBrowserDelegate протокола выглядит следующим образом:

- (NSInteger)browser:(NSBrowser *)sender numberOfRowsInColumn:(NSInteger)column 
{ 
    return [[self getSelectionInBrowser:sender] count]; 
} 

- (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item { 
    return [[self getSelectionInBrowser:browser] count]; 
} 

- (id)browser:(NSBrowser *)browser child:(NSInteger)index ofItem:(id)item { 
    return [self getSelectionInBrowser:browser]; 
} 

- (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item { 
    return ![item isKindOfClass:[NSMutableArray class]]; 
} 

- (id)browser:(NSBrowser *)browser objectValueForItem:(id)item { 
    return nil; 
} 

- (void)browser:(NSBrowser *)browser willDisplayCell:(NSBrowserCell *)cell atRow:(NSInteger)row column:(NSInteger)column { 
    NSArray *selection = [self getSelectionInBrowser:browser]; 
    cell.title = [[selection objectAtIndex:row] objectForKey:@"name"]; 
} 

Первый столбец NSBrowser заполняется с правильными именами. Однако, как только я делаю выбор, программа вылетает с ошибкой -[__NSArrayM objectAtIndex:]: index 4 beyond bounds [0 .. 0]. После некоторой отладки строка кода, с которой он падает, - это вызов objectAtIndex: в моем обычном getSelectionInBrowser:.

Это меня не удивляет, потому что еще до крушения я понял, что делаю что-то неправильно, полагаясь на этот пользовательский метод, чтобы получить текущий выбор. Я полагаю, что эта работа должна быть выполнена в самих методах делегата, и при правильной реализации текущий выбор должен быть доступен в переменной item, которая предоставляется во многих из этих методов. Однако я не мог заставить это работать. Переменная item всегда представляла собой просто корневой объект данных, а не отражала наиболее «развернутый» выбор.

Итак, как мне исправить мою реализацию?

ответ

4

Решено! Вот мой последний рабочий код. Нет необходимости в этом обычном методе getSelection..., и несколько методов делегата, которые у меня были, были лишними (только вы используете НЕ «API на основе элементов»).

- (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item { 
    if (item) { 
     return [[item objectForKey:@"children"] count]; 
    } 
    return [browserData count]; 
} 

- (id)browser:(NSBrowser *)browser child:(NSInteger)index ofItem:(id)item { 
    if (item) { 
     return [[item objectForKey:@"children"] objectAtIndex:index]; 
    } 
    return [browserData objectAtIndex:index]; 
} 

- (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item { 
    return [item objectForKey:@"children"] == nil; 
} 

- (id)browser:(NSBrowser *)browser objectValueForItem:(id)item { 
    return [item objectForKey:@"name"]; 
} 

Первый способ заключается в том, как вы указываете NSBrowser количество строк, которое должно быть. Второй метод - это то, где вы определяете, какие данные должны быть представлены в заданной строке (индексе). В обоих случаях вы должны сначала проверить, действительно ли существует item. Если это не так, это потому, что вы находитесь в корне данных (первый столбец в NSBrowser). Только при выборе строки (или элемента!) В NSBrowser переменная item будет содержать что угодно. Конечный метод должен возвращать строку, которую вы хотите показать в данной строке.

Надеюсь, это поможет людям в будущем.

+0

Люди из будущего благодарит вас за помощь. –