Перезапуск приложения какао - PullRequest
5 голосов
/ 30 июня 2010

У меня есть приложение, которое проверяет параметры командной строки и сохраняет значения в постоянных хранилищах.Одним из них является пароль, который я не хочу, чтобы его видели люди с «пс» и друзьями.Подход, который я сейчас рассматриваю, заключается в том, чтобы после того, как я сохранил нужные значения, перезапустить процесс без параметров командной строки.Мой наивный подход заключается в том, что args [0] - это путь к приложению:

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:[args objectAtIndex:0]];
[task launch];
[task release];
[NSApp terminate:nil];

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

Больше информации: Кажется, что когда я вызываю [NSApp terminate: nil], запущенный NSTask застревает, но если я просто завершаю работу (), то он работает нормально,Тем не менее, я обеспокоен тем, что открытые объекты (связка ключей, plist и т. Д.) Будут в плохом состоянии, если я сделаю это.

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

Ответы [ 4 ]

10 голосов
/ 30 июня 2010

В Интернете есть множество примеров, но этот (также ниже) выглядит так, как будто он содержит весь необходимый код. Также есть более подробные объяснения .

// gcc -Wall -arch i386 -arch ppc -mmacosx-version-min=10.4 -Os -framework AppKit -o relaunch relaunch.m

#import <AppKit/AppKit.h>

@interface TerminationListener : NSObject
{
    const char *executablePath;
    pid_t parentProcessId;
}

- (void) relaunch;

@end

@implementation TerminationListener

- (id) initWithExecutablePath:(const char *)execPath parentProcessId:(pid_t)ppid
{
    self = [super init];
    if (self != nil) {
        executablePath = execPath;
        parentProcessId = ppid;

        // This adds the input source required by the run loop
        [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidTerminate:) name:NSWorkspaceDidTerminateApplicationNotification object:nil];
        if (getppid() == 1) {
            // ppid is launchd (1) => parent terminated already
            [self relaunch];
        }
    }
    return self;
}

- (void) applicationDidTerminate:(NSNotification *)notification
{
    if (parentProcessId == [[[notification userInfo] valueForKey:@"NSApplicationProcessIdentifier"] intValue]) {
        // parent just terminated
        [self relaunch];
    }
}

- (void) relaunch
{
    [[NSWorkspace sharedWorkspace] launchApplication:[NSString stringWithUTF8String:executablePath]];
    exit(0);
}

@end

int main (int argc, const char * argv[])
{
    if (argc != 3) return EXIT_FAILURE;

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [[[TerminationListener alloc] initWithExecutablePath:argv[1] parentProcessId:atoi(argv[2])] autorelease];
    [[NSApplication sharedApplication] run];

    [pool release];

    return EXIT_SUCCESS;
}
2 голосов
/ 07 марта 2016

Я знаю, что уже поздно отвечать, но этот ответ может помочь другим.Вот полезный трюк, который может вам помочь.

С помощью команды терминала просто откройте свое приложение как новый экземпляр и завершите текущий экземпляр.*

Вот как это делается:

....        
        NSString* path = [[NSBundle mainBundle] bundlePath];

        NSString* cmd = [NSString stringWithFormat:@"open -n %@", path];

        [self runCommand:cmd];

        exit(0);
    }

    /// temrinal function

    -(NSString*)runCommand:(NSString*)commandToRun;
    {
        NSTask *task;
        task = [[NSTask alloc] init];
        [task setLaunchPath: @"/bin/sh"];

        NSArray *arguments = [NSArray arrayWithObjects:
                              @"-c" ,
                              [NSString stringWithFormat:@"%@", commandToRun],
                              nil];
        NSLog(@"run command: %@",commandToRun);
        [task setArguments: arguments];

        NSPipe *pipe;
        pipe = [NSPipe pipe];
        [task setStandardOutput: pipe];

        NSFileHandle *file;
        file = [pipe fileHandleForReading];

        [task launch];

        NSData *data;
        data = [file readDataToEndOfFile];

        NSString *output;
        output = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
        return output;
    }
2 голосов
/ 30 июня 2010

Создайте внешний процесс, который запускает ваш после его завершения.Затем прекратить.Запуск программ Какао с NSTask работает не совсем правильно.

0 голосов
/ 22 октября 2017

Для тех, кто все еще хочет использовать NSTask для повторного запуска, я нашел один из возможных способов: пожалуйста, НЕ устанавливайте NSPipe для NSTask, потому что NSTask завершит само приложение, как только приложение завершится, запущенный NSTask может застрятьтам.

По крайней мере для меня, после того, как я удалил настройки NSPipe, мое приложение успешно перезапустилось.Вот что я делаю: 1. Напишите инструмент командной строки, который имеет 3 параметра: идентификатор пакета приложения, полный путь к приложению. Обратите внимание, что в этой командной строке необходимо завершить работу приложения и подождать некоторое время, чтобы убедиться, что оно выполнено.действительно прервано перед запуском нового, я продолжаю проверять app.isTermination и sleep (1), если оно не прервано.

Запустите инструмент командной строки в приложении, используя NSTask, и установите соответствующие параметры. Не используйте NSPipe, просто создайте NSTask и запустите Приложение перезапускается сейчас
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...