Как я могу загрузить данные для NSTableView, не блокируя интерфейс? - PullRequest
0 голосов
/ 22 ноября 2010

Я инициализирую простой интерфейс с NSTableView, привязанным к контроллеру массива (который управляет массивом словарей).Я хочу загрузить содержимое массива в фоновом режиме (это очень трудоемкий процесс), обновляя представление таблицы каждые 100 или 1000 элементов.Идея в том, что интерфейс доступен и отзывчив.Я не могу понять, как также вызвать обновление / обновление после этого.Стол остается пустым.Кто-нибудь может предложить указатели?

Мой текущий подход:

// In init for my app controller. This seems to work well, but I've tried other methods here.
[self performSelectorInBackground:@selector(loadTable) withObject:nil];


- (void)loadTable {
  tracks = [[NSMutableArray alloc] initWithCapacity:[masters count]];

  // ... create each object one-by-one. Add it to tracks.
  for (... in ...) {
    [tracks addObject:newObject];
  }

  // Now I don't know what to do next. The table remains empty. 
  // Things I've tried (though possibly not in all combinations with the
  // method above):
  // 1. With a suitably-defined reloadData method, which just reloads
  //   the table view and sets needs display.
  [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];

  // 2. Reload directly.
  [tv reloadData];
  [tv setNeedsDisplay];
}

Если я просто загружаю данные напрямую и не пытаюсь сделать это в фоновом режиме, все работает нормально, ноэто занимает почти 30 секунд.

Ответы [ 2 ]

6 голосов
/ 22 ноября 2010

У вас есть столбцы таблицы (я полагаю, вы имели в виду), связанные с контроллером массива, так что именно отсюда таблица получает свои данные.Табличное представление вполне может запрашивать обновленные массивы, но оно запрашивает контроллер массива, который не знает, что что-то изменилось.

Контроллер массива не просто обернется и попросит вас свежие данные;из этого следует, что он существует исключительно для того, чтобы вам было труднее связать табличное представление с вашим массивом, а это не так.Это контроллер;его работа состоит в том, чтобы владеть (копировать) массивом и поддерживать его порядок и выбор пользователем некоторого подмножества его объектов.

Следовательно, вам нужен контроллер массива, чтобы узнать, когда вы добавляете элементы в ваш массив,Лучший способ добиться этого - привязать контроллер массива contentArray к свойству контроллера и обновить это свойство в соответствии с KVO.

Это означает:

  1. Создайте изменяемый массив в вашем методе init.(И, конечно, выпустите его в dealloc.)
  2. Реализуйте методы доступа к массиву , плюс addTracksObject: и removeTracksObject: (которые являются технически установленными методами доступа, поэтому KVOбудет игнорировать их для свойства массива) для вашего удобства.
  3. Чтобы добавить дорожку, отправьте себе сообщение addTracksObject:.Вы должны ответить на это, отправив себе сообщение insertObject:inTracksAtIndex: (с индексом [self countOfTracks] для индекса, если вы не хотите выполнять сортировку), и вы должны ответить на insertObject:inTracksAtIndex:, отправив массив tracks insertObject:atIndex:message.

Как я уже говорил, KVO будет игнорировать addFooObject: и removeFooObject:, когда foo является свойством NSArray, учитывая только эти методы доступа NSSet-свойства, поэтому вам нужно реализовать их сверхуinsertObject:inFooAtIndex: и removeObjectFromFooAtIndex:, потому что эти являются массивами доступа, что означает, что KVO будет реагировать на них.

Шаг 3, как я только что описал, будет довольно медленным, потому что онзаставит контроллер массива повторно извлекать ваше свойство, а табличное представление будет повторно выбирать arrangedObjects контроллера массива, по крайней мере, один раз для каждой добавляемой строки.

Таким образом, вы должны поддерживать добавление пакетовПоведение с этим альтернативным шагом 3:

  • Реализуйте insertTracks:atIndexes: и передайте ему массив из одной партии (например, 100 или 1000) дорожек и набор индексов, образованный [NSIndexSet indexSetWithRange:(NSRange){ [self countOfTracks], countOfBatch }].Вам также потребуется реализовать removeTracksAtIndexes:, только потому, что KVO будет игнорировать каждый метод вставки, если у вас также нет его аналога.

Вероятно, вам нужно настроить контроллер массива на попытку сохранениявыбор, чтобы не слишком расстраивать пользователя, пока вы все еще вводите строки.

Кроме того, вы можете создавать объекты в фоновом потоке, периодически отправляя себе другой пакет для добавления, используяосновной поток выполнения.Обычно я сторонник выполнения каких-либо действий в цикле выполнения основного потока, когда это возможно, но такого рода вещи могут легко замедлить работу вашего интерфейса, в то время как ваша периодическая загрузка создает другой пакет.

1 голос
/ 22 ноября 2010

Вам нужно позвонить setNeedsDisplay:YES в табличном представлении в главном потоке.Не называйте это из фонового потока.Все вызовы пользовательского интерфейса Cocoa должны выполняться в главном потоке, иначе могут произойти странные вещи.

...