从 Cocoa 应用程序(通过 NSTask)静默运行 xcodebuild 两次失败

Posted

技术标签:

【中文标题】从 Cocoa 应用程序(通过 NSTask)静默运行 xcodebuild 两次失败【英文标题】:Running xcodebuild twice from a Cocoa app (via NSTask) silently fails 【发布时间】:2012-02-27 20:52:18 【问题描述】:

我有一个 Cocoa 应用程序,它可以做很多事情,但其中使用“xcodebuild”在 XCode 中清理和重新构建一个 ios 项目。 Cocoa 应用程序是使用 XCode 4.1 开发的,并且仅在 OS X 10.7 上运行(因为 NSTask 终止处理程序)。我已经有几个月没有碰它了,在我升级到 XCode 4.2 之后,我发现只有第一个运行 xcodebuild 的 NSTask 真正做了任何事情。后续调用什么都不做。

一些细节:

正在构建的 iOS 项目位于 Cocoa 应用程序的资源包中。所以基本上,Cocoa 应用程序是一个 iOS 项目的包装器。想象一个带有红色大按钮的 GUI,上面写着:“为我构建一个 iOS 应用!” 此代码在 XCode 4.1 中完美运行。任务 1 执行,然后在任务 1 的终止处理程序中,任务 2 被调用,并且运行得很好。问题是任务 2 根本不再运行。 我已经升级到 xcode 4.3,这要求我还安装独立的 Xcode 命令行工具。代码仍然无法正常工作。 我可以毫无问题地在终端中运行“xcodebuild clean”和“xcodebuild”命令。

以下是违规代码的(转述)版本。

#import "AppDelegate.h"

@implementation AppDelegate
@synthesize window = _window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification

    [self runTaskOne];


// Clean the iOS Project
- (void) runTaskOne

NSTask *task = [[NSTask alloc] init];
[task setCurrentDirectoryPath:@".../myproject/DerivedData/myproject/Build/Products/Debug/myproject.app/Contents/Resources/iOSProjectFolder"];
[task setLaunchPath:@"/usr/bin/xcodebuild"];
[task setArguments:[NSArray arrayWithObjects:@"clean", nil]];
[task setTerminationHandler:^(NSTask *task)
 
     [self runTaskTwo];
 ];
[task launch];



// Build the same iOS project that was just cleaned
- (void) runTaskTwo;

NSTask *task = [[NSTask alloc] init];
[task setCurrentDirectoryPath:@".../myproject/DerivedData/myproject/Build/Products/Debug/myproject.app/Contents/Resources/iOSProjectFolder"];
[task setLaunchPath:@"/usr/bin/xcodebuild"];
[task launch];
 

@end

所以只是重复一遍:任务 1(清洁)工作正常。任务 2(构建)甚至没有启动。仅在升级到 XCode 4.2 后才会观察到此行为。我一定是做错了什么,但是什么?

【问题讨论】:

确实如此。实际上,我刚刚注意到任务 1 的终止处理程序从未运行。 ... Aaand 经过一番搜索,我找到了答案。现在就写吧。 【参考方案1】:

好像我在 Xcode 中遇到了一个错误,类似于以下内容: NSTask NSPipe - objective c command line help

基本上,如果 NSTask 已经启动过一次,Xcode 将保留 NSTask 的输出。

解决方案是这样切换任务的标准输入:

[task setStandardInput:[NSPipe pipe]];

我将它放入 runTaskOne 方法后,一切都开始运行良好。

【讨论】:

【参考方案2】:

如果您的项目使用 ARC(自动引用计数),NSTask 实例会在 runTaskOne 方法结束时自动释放。所以完成处理程序永远不会被调用,因为应该观察进程的对象不再存在。

您需要通过将任务存储在实例变量中来保留对任务的引用。

【讨论】:

感谢尼古拉斯的回复。我发现通过将管道作为标准输入添加到任务中,例如:[task setStandardInput:[NSPipe pipe]]; 可以解决问题。终止处理程序已运行,一切正常。

以上是关于从 Cocoa 应用程序(通过 NSTask)静默运行 xcodebuild 两次失败的主要内容,如果未能解决你的问题,请参考以下文章

Cocoa 应用程序无法开始循环 python 脚本。通过 xcode 构建/运行时工作

如何使用 Cocoa 以编程方式获取当前电池电量 [重复]

在 Cocoa 中搜索目录及其子目录中的所有目录/文件

浩瀚亦柔和——Cocoa 的数码绘画

可可沙箱嵌入式命令行不起作用

NSTask 字符输出到 NSTextField 无缓冲作为连续流