NSTask блокирует основной поток - PullRequest
6 голосов
/ 06 октября 2011

Я использую NSTask, но когда я запускаю задачу, она блокирует основной поток (поэтому я не могу его обновить), пока задача не завершится. Это мой код:

NSString *hostsforping = @"google.es";
    pingdata = [[NSTask alloc] init];
    [pingdata setLaunchPath: @"/sbin/ping"];

    NSArray *pingargs;
    pingargs = [NSArray arrayWithObjects: @"-c 5", hostsforping, nil];
    [pingdata setArguments: pingargs];

    NSPipe *pingpipe;
    pingpipe = [NSPipe pipe];
    [pingdata setStandardOutput: pingpipe];

    NSFileHandle *pingfile;
    pingfile = [pingpipe fileHandleForReading];

    [pingdata launch];

    NSData *pingdata1;
    pingdata1 = [pingfile readDataToEndOfFile];

    NSString *pingstring;
    pingstring = [[NSString alloc] initWithData: pingdata1 encoding: NSUTF8StringEncoding];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(taskDidTerminate:)
                                                 name:NSTaskDidTerminateNotification
                                               object:nil];
}
- (void) taskDidTerminate:(NSNotification *)notification {
    NSLog(@"end");
}

Я читал, что -waitUntilExit блокирует основной поток, но я им не пользуюсь, поэтому я не знаю, что я делаю неправильно.

Ответы [ 2 ]

11 голосов
/ 06 октября 2011

Запустите задачу в фоновом потоке, readDataToEndOfFile блокирует основной поток.

// Offload the method onto a background thread, could also use Grand Central Dispatch   
[self performSelectorInBackground:@selector(startTask) withObject:nil];


- (void)startTask {
    NSString *hostsforping = @"google.es";
    NSTask *pingdata = [[NSTask alloc] init];
    [pingdata setLaunchPath: @"/sbin/ping"];

    NSArray *pingargs;
    pingargs = [NSArray arrayWithObjects: @"-c 5", hostsforping, nil];
    [pingdata setArguments: pingargs];

    NSPipe *pingpipe;
    pingpipe = [NSPipe pipe];
    [pingdata setStandardOutput: pingpipe];

    NSFileHandle *pingfile;
    pingfile = [pingpipe fileHandleForReading];

    [pingdata launch];

    NSData *pingdata1;    
    pingdata1 = [pingfile readDataToEndOfFile];

    NSString *pingstring;
    pingstring = [[NSString alloc] initWithData: pingdata1 encoding: NSUTF8StringEncoding];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(taskDidTerminate:)
                                                 name:NSTaskDidTerminateNotification
                                               object:nil];
}

- (void) taskDidTerminate:(NSNotification *)notification {
    // Note this is called from the background thread, don't update the UI here
    NSLog(@"end");

    // Call updateUI method on main thread to update the user interface
    [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
}
1 голос
/ 27 августа 2015

Поскольку вы используете readDataToEndOfFile, вы неявно говорите, что вашему NSTask нужно выполнение блокировки. Я мог бы предложить вам обернуть ваш код в скобки GCD, используя dispatch_async. Например:

- (void)executeShellScript {
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        NSString *execPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"myScript.sh"];

        NSPipe *pipe = [NSPipe pipe];
        NSFileHandle *file = pipe.fileHandleForReading;

        NSTask *task = [[NSTask alloc] init];
        task.launchPath = @"/bin/sh";
        task.arguments = @[execPath];
        task.standardOutput = pipe;

        [task launch];

        NSData *data = [file readDataToEndOfFile]; //readDataToEndOfFile is blocking the main thread.
        [file closeFile];
        NSString *bashOutput = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];

        NSLog (@"shell returned:\n%@", bashOutput);
    });
}
...