2011-10-06 173 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); 
    }); 
}