【问题标题】:NSTask waitUntilExit hanging app on jailbroken iOSNSTask waitUntilExit 在越狱 iOS 上挂起应用程序
【发布时间】:2011-02-28 07:06:29
【问题描述】:

所以我让 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."); 
    }
}

【问题讨论】:

  • 您的目标是什么平台,iPhone 还是 Mac? iOS 上不允许使用 NSTask,Mac 上不存在 UIAlertView。
  • iOS。准确地说,越狱了。

标签: iphone objective-c cocoa jailbreak nstask


【解决方案1】:

不要使用waitUntilExit

问题是如何在任务完成后做某事而不阻塞 UI(或冻结那个按钮)。对于所有类似问题,解决方案是在任务完成时收到通知,然后根据该通知继续进行(显示警报)。

在这种情况下,通知是一个名为 NSTaskDidTerminateNotification 的 NSNotification。当任务退出时,无论出于何种原因,NSTask 对象都会在默认的 NSNotificationCenter 上发布此通知。您可以询问任务的终止状态,以确定它是成功、失败还是崩溃。

另请参阅:Notification Programming Topics

【讨论】:

    【解决方案2】:

    看看基于 Apple 的 Moriarity 示例代码的 AMShellWrapper。

    “将您自己的方法连接到标准输出和标准错误,获得进程终止通知等等。”

    见:http://www.cocoadev.com/index.pl?NSTask

    【讨论】:

    • 不幸的是,它不适合iOS。
    【解决方案3】:

    不要在主线程上使用waitUntilExit。这将阻止您的 UI,并冻结您的应用程序。

    您需要订阅通知NSTaskDidTerminateNotification,该通知会在任务停止执行时发布:

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(taskDidTerminate:)
                                                 name:NSTaskDidTerminateNotification
                                               object:nil];
    

    请注意,如果任务正常完成,或者作为terminate 消息的结果,可以发布通知:

    - (void) taskDidTerminate:(NSNotification *)notification {
        if (YOUR_TASK_SUCCESS_VALUE == [[notification object] terminationStatus]) {
            NSLog(@"Task succeeded.");  
            // Here you can add your checks on the creation on the files and user alerts confirmation
        } else {
            NSLog(@"Task failed."); 
        }
    }
    

    别忘了取消订阅通知;根据您订阅通知的位置,您的 dealloc 方法将是一个好地方:

    [[NSNotificationCenter defaultCenter] removeObserver:self];
    

    更新:您希望 Mac 上记录的内容在未记录的 iOS 上也能正常工作。它不起作用并不奇怪。

    您是否尝试过在后台线程中执行任务 - 并使用 waitUntilExit 方法? 如果你很幸运并且它有效,不要忘记在显示你的 UIAlert 时切换回主线程。

    【讨论】:

    • 我刚刚使用我(尝试过)使用的 NSNotification 代码编辑了 OP。我可以在调试控制台中看到正在运行的脚本,但应用程序中没有出现警报。似乎没有打电话给taskEnded:
    猜你喜欢
    • 2016-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    相关资源
    最近更新 更多