Проблемы с реализацией протокола NSBrowserDelegate
Я могу получить экземпляр NSBrowser для отображения правильных данных в первом столбце. Однако когда я выбираю один из параметров, в следующем столбце просто отображается тот же набор параметров. Я прочитал документы, просмотрел весь пример кода Apple и почти все, что смог найти в Интернете, но я просто не могу найти правильный способ реализации требуемых методов. Данные, которые я передаю в браузер, представляют собой массив словарей. Каждый словарь, в свою очередь, содержит "дочерний" ключ, который является другим массивом словарей. И у этих словарей есть свой собственный "дочерний" ключ, который также является массивом словарей и т. Д. Использование JSON в описательных целях (объекты - это словари, массивы - это массивы), это выглядит так:
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
переменная всегда казалась просто корневым объектом данных, а не отражала наиболее развернутый выбор.
Так как мне исправить мою реализацию?
1 ответ
Решил это! Вот мой последний рабочий код. Нет необходимости в этом обычае 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
переменная держать что-нибудь. Последний метод должен вернуть строку, которую вы хотите показать в данной строке.
Надеюсь, это поможет людям в будущем.