Как мне показать файлы или прогресс при перечислении содержимого каталога с помощью Cocoa NSDirectoryEnumerator?

#objective-c #cocoa #macos

#objective-c #cocoa #macos

Вопрос:

Я новичок в Cocoa / Objective-C. Я пишу для Mac OS X 10.6 с использованием Xcode 4 (и требуется сборка мусора).

Как бы я мог сделать возможным для следующего кода (основанного на примере кода Apple) обновить мой графический интерфейс, чтобы графический интерфейс отображал либо количество перечисленных файлов, либо сами имена файлов? Я уже знаю, что я не могу просто создать выход для метки и обновить текст метки. Там, где выполняются NSLog вызовы, есть места, где я мог бы захотеть обновить статус в графическом интерфейсе.

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

У меня сложилось впечатление, что NSTask подойдет для моих простых требований?

Я также захочу предоставить пользователю возможность приостановить или отменить длительную задачу.

Заранее спасибо.

Код:

 NSArray *keys = [NSArray arrayWithObjects:
    NSURLIsDirectoryKey, NSURLIsPackageKey, NSURLLocalizedNameKey, nil]; 

NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] 
                                    enumeratorAtURL:directoryURL
                         includingPropertiesForKeys:keys 
                                            options:(NSDirectoryEnumerationSkipsHiddenFiles) 
                                       errorHandler:^(NSURL *url, NSError *error) { 
                                           // Handle the error.
                                           // Return YES if the enumeration should continue after the error. 
                                     return YES; 
                                       }
                                    ]; 

for (NSURL *url in enumerator) { 
    // Error-checking is omitted for clarity. 

    NSNumber *isDirectory = nil; 
    [url getResourceValue:amp;isDirectory forKey:NSURLIsDirectoryKey error:NULL]; 

    if ([isDirectory boolValue]) { 
        NSString *localizedName = nil; 
        [url getResourceValue:amp;localizedName forKey:NSURLLocalizedNameKey error:NULL]; 

        NSNumber *isPackage = nil; 
        [url getResourceValue:amp;isPackage forKey:NSURLIsPackageKey error:NULL]; 

        if ([isPackage boolValue]) { 
            NSLog(@"Package at %@", localizedName); 
        } 
        else { 
            NSLog(@"Directory at %@", localizedName); 
        }
    }
    else {
        NSLog(@"File at %@", url);
    }
}
  

Комментарии:

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

Ответ №1:

Ответ заключается в использовании NSOperation, как показано в примере NSOperationSample. Это включает в себя помещение перечисления внутри NSOperation, помещение его в очередь и отправку в цикле перечисления NSNotifications, для наблюдения за которыми зарегистрирован контроллер окна, чтобы графический интерфейс мог обновлять счетчик и таблицу имен файлов (что вряд ли могла облегчить предлагаемая архитектура событий), когда перечислитель находит файлы. Внутри цикла перечисления он проверяет флаг isCancelled, чтобы увидеть, нажал ли пользователь кнопку «Стоп» в графическом интерфейсе, и прерывает перечисление, если да.

Ответ №2:

В этом случае вам не нужен NSTask. Прочитайте об архитектуре событий. Если вы собрали части правильно, вы все еще можете реагировать на пользовательские события во время выполнения процесса, подобного перечислению. Попробуйте.

Комментарии:

1. Спасибо пользователю 757395, но мне жаль, что я не совсем понимаю. Я прочитал предложенную ссылку, но я не понимаю, предполагаете ли вы, что длительный процесс (цикл в моем коде) вызывает события. Казалось бы, это то, что требуется для того, чтобы мой графический интерфейс мог обновляться с прогрессом.

2. упс «спасибо, дрюк». Вы, кажется, предлагаете, чтобы мой цикл был прерван (т. Е. отменен) таким событием, как нажатие пользователем кнопки «Отмена». Во время выполнения вышеупомянутого цикла мой графический интерфейс «заморожен» в ожидании завершения цикла. Во всем, что я прочитал до сих пор, обсуждается сохранение адаптивного графического интерфейса с использованием одного из потоков, GCD или NSTask. Возможно, это «правильная сборка деталей», как вы упомянули, которую мне нужно понять в первую очередь. Какие части, пожалуйста?

3. Я только что нашел пример приложения от Apple NSOperationSample , который показывает, как использовать NSOperation и NSOperationQueue для прерывания перечисления NSDirectoryEnumerator