Обновление пользовательского интерфейса, NSOutlineView reloadData и рекурсивные методы

Я заполняю NSOutlineView, рекурсивно читая каталог. После того, как каталог и его подкаталоги прочитаны, я обновляю схему, вызывая reloadData внутри отправки, как показано ниже.

-(void)readDir:(NSString*)path {
   dispatch_async(dispatch_get_main_queue(), ^{ \
      [outlineView reloadData];
   });

 //////////
 //// some internal stuff
 //////////

  NSArray* subs = [self getSubDirs:path];
  for (NSString* p in subs) {
      [self readDir:p];
  }
}

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

   - (void)startAll {
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        dispatch_async(queue, ^{
           [self readDir:@"/"];
        });
   }

Проблема в том, что иногда вызывается dispatch_async(dispatch_get_main_queue(), ...) во время чтения подкаталогов (это вообще асинхронно!) и приложение вылетает

Если я использую dispatch_sync(dispatch_get_main_queue(), ...) (обратите внимание на версию sync), контур всегда рисуется правильно, но очень-очень медленно, поэтому возникает вопрос:

как я могу изменить код так, чтобы он был как можно быстрее, и дождаться завершения dispatch_[a]sync(dispatch_get_main_queue(),...)?


person dafi    schedule 28.09.2011    source источник


Ответы (2)


Похоже, проблема в том, что пока some internal stuff выполняется в одном потоке, ваша модель находится в несогласованном состоянии, которое reloadData не может правильно обработать.

Добавляете ли вы записи каталогов в их родительский каталог до того, как они будут достаточно настроены?

person paulmelnikow    schedule 29.09.2011
comment
Действительно, проблема связана с удалением (не добавлением) элементов в массив, используемый в качестве источника данных. Я решил удалить элементы внутри кода блока, используемого в основной очереди, и, похоже, работает, но я не совсем уверен - person dafi; 29.09.2011

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

-(void)readDir:(NSString*)path {
   //////////
   //// some internal stuff
   //////////

    NSArray* subs = [self getSubDirs:path];
    for (NSString* p in subs) {
        [self readDir:p];
        // now refresh outline with newly acquired info and current data
        dispatch_sync(dispatch_get_main_queue(), ^{ \
          [outlineView reloadData];
        });
    }
}
person Smilin Brian    schedule 30.11.2012