objective-ccocoanstask

NSTask blocking the main thread


I'm using NSTask, but when I launch the task it blocks the main thread (so I can't update it) until the task ends. This is my code:

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");
}

I've been reading that -waitUntilExit does block the main thread, but I'm not using it, so I don't know what I'm doing wrong.


Solution

  • Run the task on a background thread, the readDataToEndOfFile is blocking the main thread.

    // 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];
    }