'在运行多个包含NSTask的方法运行应用程序包中的脚本时遇到问题(使用GDC更新UI)。
问题是如何一个接一个地使用,即仅在前一个完成时使用。 我说的每个方法都使用NSTask来运行sh脚本,这些脚本的持续时间为几秒,甚至可能超过一分钟(取决于完成的计算)。
我试过的一些事情很遗憾地阻止了UI,这是不正确的,因为即使是“停止”按钮也被锁定。 我正在调用以下方法:
[self performSelectorOnMainThread:@selector(runScript1:) withObject:blabla waitUntilDone:YES];
//some if statements here
[self performSelectorOnMainThread:@selector(runScript2:) withObject:blabla waitUntilDone:YES]; how to wait for runScript1 completition??
//more script to call after
编辑(添加runScript1的示例)
- (void)runScrip1:(NSArray*)args
{
if (_operationPermitted == 1) {
NSString *acq, *path;
acq = [args objectAtIndex:0];
path = [args objectAtIndex:1];
dispatch_queue_t runQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(runQueue, ^{
@try {
runScrip1Task = [[NSTask alloc] init];
Scrip1 = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Scrip1.sh"];
[_runScrip1sTask setLaunchPath:Scrip1];
[_runScrip1Task setArguments:[NSArray arrayWithObjects:@"skip", @"main", acq, path, nil]];
[_runScrip1Task setCurrentDirectoryPath:@"/private/tmp"];
[tasks addObject:_runScrip1Task];
self.outputPipe = [[NSPipe alloc] init];
_runScrip1Task.standardOutput = self.outputPipe;
_runScrip1Task.standardError = self.outputPipe;
[[self.outputPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
[[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification object:[self.outputPipe fileHandleForReading] queue:nil usingBlock:^(NSNotification *notification){
self.display2.string = @"\nAcquiring all the data...";
NSData *output = [[self.outputPipe fileHandleForReading] availableData];
NSString *outPutString = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];
// ----------------------------------------------- //
// here some code to update my UI
// ----------------------------------------------- //
dispatch_sync(dispatch_get_main_queue(), ^{
// manage text sobstitutions
[_outputView appendAttributedString:[[NSAttributedString alloc] initWithString:outPutString attributes:_whiteTextwithArialFont]];
[_displayCenter scrollToEndOfDocument:self];
});
[[self.outputPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
}];
[_runScrip1TaskTask launch];
[_runScrip1TaskTask waitUntilExit];
}
// handle errors w/o app crashes
@catch (NSException *exception) {
NSLog(@"Problem Running Task: %@", [exception description]);
[self stopAllRunningsTasks];
}
@finally {
_operationPermitted = YES;
_finished = true;
}
if (_runScrip1TaskTask.terminationStatus > 0) {
[self stopAllRunningsTasks];
}
});
}
}
任何人都可以指引我以正确的方式,而不会阻止用户界面吗? 感谢
答案 0 :(得分:1)
解决方案是让脚本保持异步,因为它们实际上是固有的,并使用“continuation”。
以下示例代码应提供一些帮助:
typedef void (^completion_t)(int result);
- (void) runScript1WithParams:(NSArray*)params completion:(completion_t)completion {
// Create and setup the task:
NSTask* task = [[NSTask alloc] init];
...
[[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification object:[self.outputPipe fileHandleForReading] queue:nil usingBlock:^(NSNotification *notification){
...
}];
// set termination handler:
task.terminationHandler = ^(NSTask* task){
if (completion) {
completion(task.terminationStatus);
}
};
// handle errors if required
...
// start the task asynchronously:
[task launch];
}
您的其他runScript
方法以相同的方式实现。
用法:
[self runScript1WithParams:params completion:^(int result){
if (result == 0) {
[self runScript2WithParams:params completion:^(int result){
if (result == ...) {
...
}
else {
...
}
}
}
}];
答案 1 :(得分:0)
这样做你想要的吗?
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self runScript1:blabla];
[self runScript2:blabla];
});
或者,您可以创建自己的串行调度队列或NSOperationQueue,其最大并发操作数为1并使用它。