Принудительно перезапустить приложение iphone программно - PullRequest
43 голосов
/ 09 декабря 2010

Я пытаюсь, чтобы приложение iPhone перезагружалось программным способом при нажатии кнопки «Выйти».

У кого-нибудь есть пример кода, которым можно поделиться?Я читал, что это возможно, изменив файл main.m, но не смог найти никакого кода, связанного с этим.

Любая помощь будет оценена.

Ответы [ 7 ]

64 голосов
/ 11 ноября 2012

Примечание:

Хотя на этот вопрос ответили как «невозможно», я думаю, что это правильный вопрос для нового разработчика iOS, и он может что-то сделать, что, вероятно,что они хотят.

Существует способ «перезапустить» ваше приложение с точки зрения пользователя, а это не технически перезапуск или выход из приложения iOS.Как указано в других ответах, приложение для iOS никогда не должно явно выходить, потому что это не разрешено в iOS.

Мой ответ:

Если вы хотите, чтобы ваше приложение вернулось назаддо состояния, в котором он находился при запуске, это не возможно на 100%, но я объясню способ получить большую часть пути, которого должно быть достаточно для всех действительных целей.

Первое, что нужно сделать, это повторно-создать свой корневой контроллер просмотра.Я рекомендую делать это с помощью метода в делегате приложения, например:

- (void)resetAppToFirstController
{
    self.window.rootViewController = [[MyMainViewController alloc] initWithNibName:nil bundle:nil];
}

Во многих случаях этого будет достаточно, но любое состояние приложения, которое у вас есть, также должно быть сброшено в этом методе.Например, выйдите из системы, сбросьте любое непостоянное состояние и аннулируйте (освободите) все объекты, которые вы можете.Этот метод также можно использовать для первоначального создания первого контроллера представления из application:didFinishLaunchingWithOptions.

Framework-классов и Singletons:

Вы не сможете полностью сброситьсостояние отдельных фреймворков или экземпляров фреймворка, таких как эти:

[UIApplication sharedApplication];
[NSNotificationCenter defaultCenter];
[NSUserDefaults standardUserDefaults];
[UIScreen screens];
// etc...

Это, вероятно, хорошо, так как в любом случае вам не следует хранить какое-либо непостоянное состояние (кроме NSNotificationCenter, новсе зарегистрированные наблюдатели должны были быть удалены, когда объекты были освобождены).Если вы хотите инициализировать или сбросить любое состояние структуры, вы можете сделать это тем же методом resetAppToFirstController.В любом случае, не нужно создавать их заново, или объект window.

Если у вас есть какой-либо из ваших собственных синглетонов, вы можете воссоздать их, сохранив их в классе-одиночном держателе.(который сам по себе настоящий синглтон).Концептуально, это простой одноэлементный класс со свойствами для каждого из ваших других синглетонов и reset метод для аннулирования и освобождения их всех.Ваши другие синглтоны должны использовать этот класс (вместо статической или глобальной переменной) для хранения экземпляров синглтона.Будьте осторожны, если вы используете какие-либо сторонние библиотеки, так как они могут также использовать синглтоны, и вам нужно будет убедиться, что они также используют ваш синглтон-держатель, чтобы вы могли сбросить их при необходимости.Я думаю, что эта техника в любом случае является хорошей практикой, потому что в некоторых случаях (например, модульное тестирование) вы хотите, чтобы объекты, которые обычно были одиночными, исчезали и повторно инициализировались в первоначальное состояние.Однако вы не хотите связывать одноэлементные реализации с вашим одноэлементным держателем, поэтому хорошим способом реализации этого является использование NSMutableDictionary в качестве связанного объекта в [UIApplication sharedApplication] с именами одноэлементных классов в качестве ключей.Однако я немного отклоняюсь от темы, поскольку это более продвинутый метод, выходящий за рамки этого вопроса.


Вышеприведенного должно быть достаточно, чтобы «перезагрузить» ваше приложение настолько, насколько это возможно пользователю.обеспокоен.Вы даже можете снова показать заставку, если хотите в качестве первого контроллера просмотра.

17 голосов
/ 09 декабря 2010

Прежде всего, хотя Apple может убить ваше приложение, это не разрешено Apple и будет отклонено. Даже если оно не было отклонено, невозможно перезапустить ваше приложение, как только оно будет убито. Вам просто нужно найти способ перезагрузить ваше приложение через код, как сказал Jason Coco. Это может быть больше работы, но оно того стоит, чтобы не быть отвергнутым Apple.

15 голосов
/ 04 января 2012

попробуй это, у меня работает.

-(void)restart
{
    MyAppDelegate *appDelegate = (MyAppDelegate *)([UIApplication sharedApplication].delegate);
    [appDelegate.navigationController popToRootViewControllerAnimated:NO];
    UIViewController *topViewController = appDelegate.navigationController.topViewController;
    Class class = [topViewController class];
    NSString *nibName = topViewController.nibName;
    UIViewController *rootViewcontroller = (UIViewController *)([[class alloc] initWithNibName:nibName bundle:nil]);
    [appDelegate.navigationController.view removeFromSuperview];
    appDelegate.navigationController.viewControllers = [NSArray arrayWithObject:rootViewcontroller];
    [appDelegate.window addSubview:appDelegate.navigationController.view];
    [appDelegate.window makeKeyAndVisible];
}
9 голосов
/ 31 августа 2015

Objective-C:

exit(0);

Swift:

exit(0)

У меня есть это на 2 живых приложениях, и они не были отклонены.У одного из моих приложений даже есть эта строка кода в качестве функции на главной странице моего приложения.Он расположен в верхнем правом углу, где кнопка твит находится в Twitter.Поэтому не беспокойтесь об отклонении Apple, если только это не выглядит как неожиданный сбой.

enter image description here

5 голосов
/ 08 апреля 2015

Вот как вы можете сделать это на симуляторе с помощью частного API:

    NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@", scheme, endpointString]];

    Class pClass = NSClassFromString(@"BKSSystemService");
    id service = [[pClass alloc] init];

    SEL pSelector = NSSelectorFromString(@"openURL:application:options:clientPort:withResult:");
    NSMethodSignature *signature = [service methodSignatureForSelector:pSelector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = service;
    NSString *app = @"com.apple.mobilesafari";
    [invocation setSelector:pSelector];
    [invocation setArgument:&URL atIndex:2];
    [invocation setArgument:&app atIndex:3];
    unsigned int i = [service performSelector:NSSelectorFromString(@"createClientPort")];
    [invocation setArgument:&i atIndex:5];
    [invocation invoke];
    exit(0);

Это также должно работать на взломанных приложениях с соответствующими правами.

Для других приложений можно использовать простую HTML-страницу:

    NSString *format = @"https://dl.dropboxusercontent.com/s/rawt1ov4nbqh4yd/launchApp.html?scheme=%@&URL=%@";
    NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:format, scheme, endpointString]];
    [[UIApplication sharedApplication] openURL:URL];
    exit(0);

К сожалению, в этом случае требуется подключение к Интернету.

3 голосов
/ 11 мая 2017

Я завершаю работу во время -applicationWillResignActive: , если приложение находится на начальном экране, и Apple принимает его годами.Для пользователя это не будет похоже на сбой.В следующий раз пользователь запускает приложение с помощью значка.Дополнительная проверка, которая не завершает работу приложения, если оно было запущено сегодня, может быть полезна для удобства пользователей в некоторых случаях.

- (void)applicationWillResignActive:(UIApplication *)application
{
    // called if phone-call comes in!
    if([gameController isGameFinished])
        exit(0);
}
0 голосов
/ 24 января 2019

Поместите это в UIAlertAction, спрашивая пользователя "Сохранить и выйти". Он оживит выход (0), поэтому, по крайней мере, он выглядит запланированным.

- (void)saveAndQuit
{
    [UIView animateWithDuration:0.8 animations:^{
        self.window.alpha = 0.0; // fade out...
        // ... while pinching to a point
        self.window.transform = CGAffineTransformScale(
                CGAffineTransformMakeTranslation( 0, 0 ), 0.1, 0.1 );
    } completion:^(BOOL finished) {
        exit(0);
    }];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...