2011-10-06 172 views
5

我正在使用NSTask,但是当我启动任务时,它会阻塞主线程(所以我无法更新它),直到任务结束。这是我的代码: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不会阻塞主线程,但我不使用它,所以我不知道我做错了。

回答

11

在后台线程上运行任务,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]; 
} 
+0

或者,使用readabilityHandler,当您的任务有数据响应时,它将自动执行。东西写在管道中。 –

1

因为您使用readDataToEndOfFile,所以隐含地说您的NSTask需要阻塞执行。我可以建议你使用dispatch_async将代码包装在GCD括号中。例如:

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