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.
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];
}
Since, you use the readDataToEndOfFile, you're implicit saying that your NSTask need a blocking execution. I could suggest you to wrap your code around GCD brackets, using dispatch_async. For example:
- (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);
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With