Проблемы с реализацией протокола 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 переменная держать что-нибудь. Последний метод должен вернуть строку, которую вы хотите показать в данной строке.

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

Другие вопросы по тегам