NSTask waitUntilExit 在越狱 iOS 上挂起应用程序
所以我让 NSTask 运行一个脚本,该脚本生成一个列表,并将其放入我读取的 txt 中。但是,如果我使用当前的代码(如下),则会在 NSTask 完成之前弹出警报,从而导致空白警报。我尝试过 waitUntilExit,但这会使调用此操作的按钮冻结,但 UI 不会自行锁定。
- (void) runSupported {
stask = [[NSTask alloc] init];
[stask setLaunchPath:@"/bin/bash"];
NSString *script;
script = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/apps.sh"];
NSArray *sargs = [NSArray arrayWithObjects:script, @"-txt", nil];
[stask setArguments: sargs];
[stask launch];
NSString *apps;
apps = [NSString stringWithContentsOfFile:@"/var/mobile/supported.txt" encoding:NSUTF8StringEncoding error:nil];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:apps]) {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:@"App List" message:apps delegate:self cancelButtonTitle:@"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
} else {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:@"App List" message:@"Error generating list." delegate:self cancelButtonTitle:@"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
}
}
知道如何在调用警报之前完成 NSTask 吗?谢谢。
编辑:带有 NSNotification 的代码:
-(IBAction) supported {
stask = [[NSTask alloc] init];
[stask setLaunchPath:@"/bin/bash"];
NSString *script;
script = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/apps.sh"];
NSArray *sargs = [NSArray arrayWithObjects:script, @"-txt", nil];
[stask setArguments: sargs];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(taskEnded:)
name: NSTaskDidTerminateNotification
object: nil];
[stask launch];
}
- (void)taskEnded:(NSNotification *)notification {
if (stask == [[notification object] terminationStatus]) {
NSString *apps;
apps = [NSString stringWithContentsOfFile:@"/var/mobile/supported.txt" encoding:NSUTF8StringEncoding error:nil];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:apps]) {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:@"Apps" message:apps delegate:self cancelButtonTitle:@"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
} else {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:@"Apps" message:@"Error generating list." delegate:self cancelButtonTitle:@"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
}
} else {
NSLog(@"Task failed.");
}
}
So I've got NSTask to run a script which generates a list of something, into a txt, which I read from. But if I use my current code (below), the alert pops up before the NSTask is finished, thus resulting in a blank alert. I've tried waitUntilExit
but that makes the button that invokes this action freeze, but the UI doesn't lock up itself.
- (void) runSupported {
stask = [[NSTask alloc] init];
[stask setLaunchPath:@"/bin/bash"];
NSString *script;
script = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/apps.sh"];
NSArray *sargs = [NSArray arrayWithObjects:script, @"-txt", nil];
[stask setArguments: sargs];
[stask launch];
NSString *apps;
apps = [NSString stringWithContentsOfFile:@"/var/mobile/supported.txt" encoding:NSUTF8StringEncoding error:nil];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:apps]) {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:@"App List" message:apps delegate:self cancelButtonTitle:@"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
} else {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:@"App List" message:@"Error generating list." delegate:self cancelButtonTitle:@"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
}
}
Any idea how I'd have the NSTask finish before invoking the alert? Thanks.
Edit: Code with NSNotification:
-(IBAction) supported {
stask = [[NSTask alloc] init];
[stask setLaunchPath:@"/bin/bash"];
NSString *script;
script = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/apps.sh"];
NSArray *sargs = [NSArray arrayWithObjects:script, @"-txt", nil];
[stask setArguments: sargs];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(taskEnded:)
name: NSTaskDidTerminateNotification
object: nil];
[stask launch];
}
- (void)taskEnded:(NSNotification *)notification {
if (stask == [[notification object] terminationStatus]) {
NSString *apps;
apps = [NSString stringWithContentsOfFile:@"/var/mobile/supported.txt" encoding:NSUTF8StringEncoding error:nil];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:apps]) {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:@"Apps" message:apps delegate:self cancelButtonTitle:@"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
} else {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:@"Apps" message:@"Error generating list." delegate:self cancelButtonTitle:@"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
}
} else {
NSLog(@"Task failed.");
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不要使用
waitUntilExit
。问题是如何在任务完成后执行某些操作而不阻塞 UI(或冻结该按钮)。对于所有类似的问题,解决方案是在任务完成时收到通知,并进一步处理(显示警报)以响应该通知。
在本例中,通知是一个名为 NSTaskDidTerminateNotification 的 NSNotification。当任务由于任何原因退出时,NSTask 对象会在默认的 NSNotificationCenter 上发布此通知。您可以询问任务的终止状态是什么,以确定它是成功、失败还是崩溃。
另请参阅:通知编程主题。
Don't use
waitUntilExit
.The problem is how to do something after the task finishes without blocking the UI (or freezing that one button). The solution, as for all similar problems, is to be notified when the task finishes, and proceed further (show the alert) in response to that notification.
The notification, in this case, is an NSNotification named
NSTaskDidTerminateNotification
. When the task exits, for any reason, the NSTask object will post this notification on the default NSNotificationCenter. You can ask the task what its termination status was to determine whether it succeeded, failed, or crashed.See also: Notification Programming Topics.
看一下 AMShellWrapper,它基于 Apple 的 Moriarity 示例代码。
“将您自己的方法连接到 stdout 和 stderr,获得有关进程终止等的通知。”
请参阅:http://www.cocoadev.com/index.pl?NSTask
Have a look at AMShellWrapper which is based on Apple's Moriarity sample code.
"Connect your own methods to stdout and stderr, get notified on process termination and more."
See: http://www.cocoadev.com/index.pl?NSTask
不要在主线程上使用
waitUntilExit
。这将阻止您的 UI,并冻结您的应用程序。您需要订阅通知NSTaskDidTerminateNotification,当任务停止执行时发布:
请注意,如果任务正常完成,则可以发布通知,或者作为
terminate
消息的结果:不要忘记取消订阅通知;根据您订阅通知的位置,您的
dealloc
方法中应该是一个好地方:更新: 您希望 Mac 上记录的内容在 iOS 上也能同样工作,没有记录的地方。并不奇怪它不起作用。
您是否尝试过在后台线程中执行任务并使用 waitUntilExit 方法?
如果你幸运并且它有效,请不要忘记在显示 UIAlert 时切换回主线程。
Don't use
waitUntilExit
on your main thread. That will block your UI, and freeze your app.You need to subscribe to the notification NSTaskDidTerminateNotification, which is posted when the task has stopped execution:
Note that the notification can be posted if the task completed normally, or as the result of a
terminate
message:Don't forget to unsubscribe to the notification ; depending on where you subscribe to the notification, a good place would be in your
dealloc
method:Update: You expect something that is documented on Mac to work the same on iOS, where it is not documented. Not really surprised it doesn't work.
Have you tried to execute the task - and use the
waitUntilExit
method - in a background thread?If you are lucky and it works, don't forget to switch back to the main thread when showing your UIAlert.