【问题标题】:Force iphone app to restart programmatically?强制iphone应用程序以编程方式重新启动?
【发布时间】:2011-05-22 22:13:44
【问题描述】:

我试图让我的 iPhone 应用程序在按下注销按钮时以编程方式重新启动。

有人有代码示例可以分享吗?我读过可以通过修改 main.m 文件来实现,但我找不到任何与此相关的代码。

任何帮助将不胜感激。

【问题讨论】:

  • 您实际上不能强制它重新启动。你可以强迫它死,但你可能会因此而被拒绝。相反,您应该设计您的应用程序,以便您可以通过编程方式清除所有数据状态并自行重置。
  • 只要崩溃是由用户发起的,就不应该被拒绝。例如,银行应用程序可能会提醒用户某些内容不同步,或者自上次活动以来时间已过长,并且必须再次登录,并提供“立即退出”按钮(作为唯一选择) .这不是问题,因为用户希望它发生。并不是说这是重置/注销的最佳或唯一方法,但就 Apple 而言,我上次检查时这是可以接受的。

标签: iphone objective-c ios4 application-restart


【解决方案1】:

注意:

虽然这已被回答为“不可能”,但我认为对于新的 iOS 开发人员来说这是一个有效的问题,他们可以做的事情可能正是他们想要的。

有一种方法可以从用户的角度“重启”您的应用,而技术上不是重启或退出 iOS 应用。正如其他答案所指出的那样,iOS 应用程序永远不应明确退出,因为这在 iOS 上是不允许的。

我的回答:

如果您希望您的应用恢复到启动时的状态,这不是 100% 可能的,但我将解释一种方法,让您可以充分满足所有有效目的。

首先要做的是重新创建你的根视图控制器。我建议从应用程序委托中的方法执行此操作,如下所示:

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

在许多情况下,这已经足够了,但是您拥有的任何应用程序状态也应该在此方法中重置。例如,注销用户,重置任何非持久状态,并尽可能取消(释放)所有对象。此方法也可用于从application:didFinishLaunchingWithOptions 初始创建您的第一个视图控制器。

框架类和单例:

您将无法完全重置任何框架单例或每个应用实例的状态,例如:

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

这可能很好,因为无论如何您都不应该在这些中存储任何非持久状态(NSNotificationCenter 除外,但在释放对象时应该删除所有已注册的观察者)。如果您确实想要初始化或重置任何框架状态,您可以使用相同的 resetAppToFirstController 方法来完成。无论如何,应该没有必要重新创建这些或window 对象。

如果您有任何自己的单例,您可以通过将它们存储在单例持有者类(它本身就是一个真正的单例)中来重新创建它们。从概念上讲,这是一个简单的单例类,其中包含每个其他单例的属性和一个 reset 方法来取消和释放它们。您的其他单例应使用此类(而不是静态或全局变量)来存储单例实例。如果您使用任何第三方库,请小心,因为它们也可能使用单例,您需要确保这些库也使用您的单例持有者,以便您可以根据需要重置它们。我认为这种技术无论如何都是很好的做法,因为在某些情况下(例如单元测试),您确实希望通常是单例的对象消失并重新初始化为原始状态。但是,您不想将单例实现与单例持有者耦合,因此实现此目的的一个好方法是使用NSMutableDictionary 作为[UIApplication sharedApplication] 上的关联对象,并将单例类名作为键。但是,我有点跑题了,因为这是超出本问题范围的更高级的技术。


就用户而言,以上内容应该足以“重置”您的应用程序。如果你想作为你的第一个视图控制器,你甚至可以再次显示启动画面。

【讨论】:

    【解决方案2】:

    首先,虽然可以强制杀死你的应用程序,但这是苹果不允许的,会被拒绝。即使它没有被拒绝,一旦它被杀死,也没有办法重新启动你的应用程序。正如Jason Coco 所说,您只需要找到某种方法通过您的代码重置您的应用程序。这可能需要更多的工作,但不被 Apple 拒绝是值得的。

    【讨论】:

    • 对上述评论的补充,该评论被过早地切断了:“永远不要以编程方式退出 iOS 应用程序,因为人们倾向于将其解释为崩溃。但是,如果外部环境阻止您的应用程序按预期运行,你需要告诉你的用户这种情况,并解释他们能做些什么。”所以不要意外地退出你的用户,但如果这是用户发起的操作,并有解释,那么 Apple 没有问题。我们在 4 个已获批准的应用中使用了 exit(0)。
    【解决方案3】:

    试试这个,它对我有用。

    -(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];
    }
    

    【讨论】:

    • 是的,我知道,我们的想法是将应用设置为尽可能接近“初始”状态的状态...只有当您的应用基于导航控制器时,此技巧才有效但这个想法很容易适用于其他情况。
    【解决方案4】:

    目标-C:

    exit(0);
    

    斯威夫特:

    exit(0)
    

    我在 2 个正在运行的应用中都有此功能,并且没有被拒绝。我的一个应用程序甚至将这行代码作为我的应用程序主页中的一项功能。它位于右上角,推特按钮在 Twitter 上。所以不要担心 Apple 会拒绝,除非它看起来像是意外崩溃。

    【讨论】:

    • 不是重启,是退出
    • 这可能会拒绝 App Store 中的应用?
    【解决方案5】:

    以下是使用私有 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);
    

    很遗憾,在这种情况下需要互联网连接。

    【讨论】:

    • 这是一个有趣的内部视图。当然,它使用的是私有的 Apple API,它会被拒绝放入 AppStore。我赞成它,因为我需要一个仅用于测试目的的解决方案。不幸的是,您的第一个代码不再适用于 iOS 9(可能方法签名已更改……) - 它适用于 iOS 8.4 模拟器。第二个适用于任何模拟器,但找出 HTML 代码应该做什么有点棘手……
    【解决方案6】:

    如果应用程序在开始屏幕上并且 Apple 多年来一直接受它,我会在 -applicationWillResignActive 期间退出:。对用户来说,它看起来不像是崩溃。下次用户从图标启动应用程序时。在某些情况下,如果应用程序今天启动,则不会退出应用程序的额外检查可能对用户体验有用。

    - (void)applicationWillResignActive:(UIApplication *)application
    {
        // called if phone-call comes in!
        if([gameController isGameFinished])
            exit(0);
    }
    

    【讨论】:

    • 是退出,不是重启
    • 此时由您来保存应用程序的状态并在下次启动时恢复它,这实际上是重新启动。在旧版本的 iOS 中,您必须保存状态,因为在应用之间切换涉及退出。
    【解决方案7】:

    将其放入 UIAlertAction 中,询问用户“保存并退出”。它将为 exit(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);
        }];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      相关资源
      最近更新 更多