Есть ли способ запустить два или более NSTasks? - PullRequest
1 голос
/ 07 марта 2012

Вы можете запустить скрипт в приложении Какао, используя замечательный NSTask, и он прекрасно работает. Единственная проблема заключается в том, что мне нужно запустить несколько сценариев, и в моем приложении сценарии нельзя объединить в один файл или один вызов - они должны запускаться приложением как отдельные задачи.

Проблема в том, что, очевидно, вы можете запустить только один NSTask в приложении. Я не понимаю, почему это так, но, к сожалению, похоже. Я перепробовал все для его отладки, но независимо от того, какой сценарий, насколько он прост или сложен, мое приложение будет просто выполнять только первый NSTask, который я запустил. Эта проблема возникла до , хотя и не так прямо, и, похоже, решения не было.

Должен быть способ запустить более одного сценария в приложении. Кто-нибудь знает способ, которым я могу обойти это, или, возможно, альтернативный способ запустить скрипт? Все, что мне нужно сделать, это запустить очень короткий bash-скрипт, который выполняет "make install".

Вот пример того, как я запускаю NSTask, на случай, если это поможет.

NSTask *task;
task = [NSTask launchedTaskWithLaunchPath: @"/bin/bash"
                                arguments:[NSArray arrayWithObjects: scriptPath, nil]
        ];

Он действительно работает для всех моих сценариев в отдельности, он просто не может запускаться один за другим.

Ответы [ 4 ]

5 голосов
/ 07 марта 2012

Конечно, вы можете использовать более одного NSTask. Просто используйте метод init вместо удобного метода и установите свойства вручную:

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/true"];
[task launch];
1 голос
/ 07 марта 2012

Здесь есть некоторая путаница по поводу "только один раз".

NSTask создает новый процесс, это тот процесс, который может быть запущен только один раз; Вы можете использовать NSTask, чтобы создать столько разных процессов, сколько захотите, и каждый из них может запускаться один раз. И каждый из этих разностных процессов, которые вы создаете, может выполнять разные или одинаковые двоичные файлы - поэтому, если вы хотите создать много процессов, каждый из которых выполняет /bin/bash, вы можете.

Так что для каждого из ваших скриптов создайте новый NSTask и запустите его.

Примечание: метод класса launchedTaskWithLaunchPath:arguments создает NSTask и запускает процесс. Вы также можете создать NSTask с помощью [NSTask new] (или [[NSTask alloc] init]), установить его параметры, а затем запустить его.

Примечание: из вашего комментария к другому ответу использование [NSTask new] или [[NSTask alloc] init] означает нормальное , и вы делаете это независимо от того, используете ли вы сборщик мусора, автоматический подсчет ссылок или ручной подсчет ссылок. Это методы retain, release и autorelease, которые вы не используете для сборки мусора и автоматического подсчета ссылок.

Ответ на комментарий

user1168440 показал более общий метод вызова NSTask, но в качестве подтверждения использования метода класса здесь выполняются два сценария оболочки. Сначала создайте два сценария в /tmp:

tmp $ cat script1.sh
#!/bin/bash
echo `date -u` script one >>/tmp/script.txt
tmp $ cat script2.sh
#!/bin/bash
echo `date -u` script two >>/tmp/script.txt

И тривиальное приложение Obj-C:

#import "TasksAppDelegate.h"

@implementation TasksAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   [NSTask launchedTaskWithLaunchPath:@"/bin/bash" arguments:[NSArray arrayWithObject:@"/tmp/script1.sh"]]; 
   [NSTask launchedTaskWithLaunchPath:@"/bin/bash" arguments:[NSArray arrayWithObject: @"/tmp/script2.sh"]]; 
}

@end

Запустите в Xcode и проверьте результат:

tmp $ cat script.txt
Sat Mar 10 05:12:43 UTC 2012 script two
Sat Mar 10 05:12:43 UTC 2012 script one

Обе задачи были выполнены, так что это не то, что остановило работу вашего кода. Может быть, один из ваших сценариев оболочки, необходимый для чтения из стандартного ввода, завершился с ошибкой и, таким образом, вообще не работал?

В общем случае метод, который устанавливает канал, является выводом захвата (и может обеспечить ввод), является гораздо лучшим способом использования NSTask, но launchedTaskWithLaunchPath:arguments работает нормально, если захват вывода (или ввод ввода) не требуется.

0 голосов
/ 25 сентября 2014

попробуйте использовать концепцию потоков. Назначая каждый NStask в отдельном потоке, вы можете запустить два или более NStask.

0 голосов
/ 08 марта 2012

Вот простой подход, который я использую для запуска нескольких команд с помощью NSTask:

First setup a method to accept your commands
-(NSString *) runForOutput:(NSString *)command {

//initialize the command line to run
NSString *runCmd = [[NSString alloc] initWithString:@"/bin/bash"];
NSArray *runArgs = [[NSArray alloc] initWithObjects:@"-c",command,nil];

//update proper label
return [self runThisCmd:runCmd withArgs:runArgs];
}

next setup a method to call NSTask
-(NSString *) runThisCmd:(NSString *) runString withArgs:(NSArray *)runArgs  {

NSTask *task = [NSTask new];
[task setLaunchPath:runString];
[task setArguments:runArgs];
[task setStandardOutput:[NSPipe pipe]];
[task setStandardInput: [NSPipe pipe]];
[task setStandardError: [task standardOutput]];
[task launch];

NSData *stdOuput = [[[task standardOutput] fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];  
NSString *outputString = [[NSString alloc] initWithData:stdOuput encoding:NSUTF8StringEncoding];
return outputString;
}

Now run a bunch of commands
- (void) runSomething {

    NSString *hostnameLong = [self runForOutput:@"hostname"];
    NSString *hostnameShort = [self runForOutput:@"hostname -s"];
    NSString *startDate = [self runForOutput:@"date '+Start Date: %Y-%m-%d'"];
    NSString *startTime = [self runForOutput:@"date '+Start Time: %H:%M:%S'"];

}

The output of the commands are in the strings. You can work with it from there.
This method is best for short, quick command lines due to the [task waitUntilExit]
call that will block. This works great to simulate what I call "unix one-liners". 
I use it sometimes from awakeFromNib to grab one to two bits of info I may need. 
For long running scripts you would convert to an async approach and use notifications to update variables.
...