Использование NSTask и NSPipe приводит к 100% загрузке процессора

Я пытаюсь запустить простой скрипт bash с помощью NSTask и направить вывод в текстовое представление. Как только задача выполнена, загрузка моего приложения ЦП составляет 100%, хотя это echo (теперь).

Я создал совершенно новый проект, чтобы изолировать проблему:

@interface AppDelegate ()
@property (nonatomic) NSTask *task;
@property (nonatomic) NSPipe *pipe;
@end

@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    self.pipe = [NSPipe pipe];
    self.pipe.fileHandleForReading.readabilityHandler = ^(NSFileHandle *h) {
        NSLog(@"Read: %@", [h readDataToEndOfFile]);
    };

    self.task = [[NSTask alloc] init];
    self.task.launchPath = @"/bin/bash";
    self.task.arguments = @[@"-c", @"echo test"];
    self.task.standardOutput = self.pipe;
    [self.task launch];
}
@end

Он правильно выполнен и выводится (как NSData) зарегистрирован NSLog:

PipeTest[3933:2623] Read: <74657374 0a>

Однако загрузка процессора остается на уровне 100%, пока я не завершу свое приложение.

РЕДАКТИРОВАТЬ:

Тест Time Profiler возвращает список ниже, но я не уверен, как это интерпретировать.

2 ответа

Решение

Дескриптор файла оставлен открытым?

@interface AppDelegate ()
@property (nonatomic) NSTask *task;
@property (nonatomic) NSPipe *pipe;
@end

@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    self.pipe = [NSPipe pipe];
    self.pipe.fileHandleForReading.readabilityHandler = ^(NSFileHandle *h) {
        NSLog(@"Read: %@", [h readDataToEndOfFile]);
        [h closeFile];
    };

    self.task = [[NSTask alloc] init];
    self.task.launchPath = @"/bin/bash";
    self.task.arguments = @[@"-c", @"echo test"];
    self.task.standardOutput = self.pipe;
    [self.task launch];
}

Закрытие файла на NSFileHandleh Кажется, чтобы вернуть ваш процессор в нормальное русло.

Предлагаемый код не будет работать, если приложение записывает больше, чем буфер реализации NSFileHandle (4K в моем наблюдении за El Capitan). [h readDataToEndOfFile] имеет тенденцию читать 4K за раз, поэтому этот пример может преждевременно закрыть буфер. Более надежный и одинаково недокументированный подход для вашего обработчика:

NSData *data = [h readDataToEndOfFile];
if (data.length) {
  NSLog(@"Read: %@", data);
} else {
  [h closeFile];
}
Другие вопросы по тегам