正确的退出iPhone应用程序的方法是什么?

292

我正在编写一个iPhone应用程序,并且需要由于某些用户操作强制退出它。在清理了应用程序分配的内存后,调用哪种适当的方法来终止应用程序?

答案:

在清理了应用程序分配的内存之后,可以使用exit(0)方法来终止应用程序。


35
唯一正确的方式是——使用主页按钮。 - beryllium
5
我能想象到唯一一个可能会让人考虑以编程方式退出的情况是以下场景:应用程序启动,显示使用条款,拒绝接受后退出应用程序。这是一些品牌有时会向开发者施加压力要求做的事情。但这是错误的。 - Daniel
6
通常情况下,当您上传应用程序时,您需要在iTunes Connect上放置免责声明/使用条款(EULA)。如果用户下载您的应用程序,则意味着他们已接受您的EULA。 - Paul de Lange
9
有完全合理的原因需要强制退出iOS应用程序。我的情况是,我正在分发预发布的beta版本应用程序。beta版本开放了所有IAP免费使用,但这些功能有时间限制,需要在几周后过期。因此,我使用下面的方法在beta期结束后终止应用程序。我会在LIVE版本中删除这个功能。但是这个方法对我很有帮助,而且是正确的! - badweasel
6
如果一个应用是长时间后台运行的,且进入不再需要在后台运行的状态,这是退出应用的一个有效理由。例如,用户注销登录。这种情况下退出应用程序是有意义的,因为当下次启动应用程序时,它将开始一个干净的状态。这将作为一种安全措施,防止内存泄漏等问题发生。请注意,在这种情况下,应用程序将会退出“后台”,因此用户不会察觉到任何问题。 - frankodwyer
显示剩余4条评论
24个回答

6

苹果公司表示:

"警告:不要调用exit函数。调用exit的应用程序将显示为已崩溃,而不是执行优雅终止并动画返回主屏幕。"

我认为这是一个错误的假设。如果用户点击退出按钮,并出现一条消息,如“应用程序现在将退出”,它不会显得崩溃。苹果应该提供一种有效的退出应用程序的方式(不是exit(0))。


3
Home键是指位于任何i设备底部的按钮,因此不需要在设备中构建自己的退出按钮。 - Popeye

5

不应直接调用函数exit(0),因为它会立即退出应用程序并看起来像是您的应用程序已崩溃。最好显示一个确认提示框,让用户自己执行此操作。

Swift 4.2

func askForQuit(_ completion:@escaping (_ canQuit: Bool) -> Void) {
    let alert = UIAlertController(title: "Confirmation!", message: "Do you want to quit the application", preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: { (action) in
        alert.dismiss(animated: true, completion: nil)
        completion(true)
    }))
    alert.addAction(UIAlertAction(title: "No", style: UIAlertAction.Style.cancel, handler: { (action) in
        alert.dismiss(animated: true, completion: nil)
        completion(false)
    }))
    self.present(alert, animated: true, completion: nil)
}

/// Will quit the application with animation
func quit() {
    UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
    /// Sleep for a while to let the app goes in background
    sleep(2)
    exit(0)
}

用法:

self.askForQuit { (canQuit) in
     if canQuit {
         self.quit()
     }
}

4
这个问题已经得到了很好的回答,但我决定再扩展一下:
如果你没有仔细阅读苹果的iOS人机界面指南(他们保留拒绝任何违反规定行为的权利),则无法使你的应用程序被AppStore接受。在“不要通过编程退出”这一节中,有一个确切的指南,告诉你在这种情况下该如何处理。可以在此链接查看:http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices.html 如果您遇到苹果平台上难以找到解决方案的问题,请参考HIG。苹果可能只是不希望您这样做,并且通常(我不是苹果,所以不能保证总是)会在其文档中说明。

3
使用 exit(0)abort() 函数退出应用是不被苹果鼓励的,虽然在开发和测试过程中可以使用这些函数。

如果在开发或测试期间需要终止您的应用程序,则建议使用 abort 函数或 assert 宏。

请查看此 Apple Q&A 链接获取更多信息。
由于使用这些函数会造成应用程序崩溃的印象,因此我得到了一些建议,例如我们可以显示警报窗口并展示关闭应用程序的消息以提醒用户,由于某些功能不可用而需要关闭应用程序。
但是,iOS 人机界面指南 Starting And Stopping App 建议永远不要使用 Quit 或 Close 按钮来终止应用程序。相反,他们建议显示适当的消息以解释情况。

iOS 应用程序从不显示“关闭”或“退出”选项。人们在切换到另一个应用程序、返回主屏幕或将设备置于睡眠模式时停止使用应用程序。

永远不要以编程方式退出 iOS 应用程序。人们往往将其解释为崩溃。如果某些情况阻止您的应用程序按预期工作,您需要告知用户有关该情况并解释他们可以采取什么措施。


3

如果你的应用程序需要互联网连接,那么你可能需要退出应用程序。你可以显示一个警报,然后执行以下操作:

if ([[UIApplication sharedApplication] respondsToSelector:@selector(terminate)]) {
    [[UIApplication sharedApplication] performSelector:@selector(terminate)];
} else {
    kill(getpid(), SIGINT); 
}

9
不用终止它。例如,当iTunes应用程序无法检测到适当的连接时,它会简单地显示一个屏幕,表明他们未连接。它不会退出,只是向用户提供了正在发生的情况。然后,用户通过点击主屏幕按钮退出。 - August
1
指南针应用程序会退出,如果它无法正常工作。 - Josh Lee

2

除了上面提到的好回答外,我想补充一点,考虑清理你的内存。

当你的应用程序退出时,iPhone操作系统会自动清理应用程序留下的任何内容,因此手动释放所有内存只会增加应用程序退出所需的时间。


请在当前的IOS4.0及以上版本下修改您的回答。:P - rptwsthi

2
- (IBAction)logOutButton:(id)sender
{
   //show confirmation message to user
   CustomAlert* alert = [[CustomAlert alloc] initWithTitle:@"Confirmation" message:@"Do you want  to exit?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
   alert.style = AlertStyleWhite;
   [alert setFontName:@"Helvetica" fontColor:[UIColor blackColor] fontShadowColor:[UIColor clearColor]];
   [alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{

   if (buttonIndex != 0)  // 0 == the cancel button
   {
      //home button press programmatically
      UIApplication *app = [UIApplication sharedApplication];
      [app performSelector:@selector(suspend)];
      //wait 2 seconds while app is going background
      [NSThread sleepForTimeInterval:2.0];
      //exit app when app is in background
      NSLog(@"exit(0)");
      exit(0);
  }
}

1
我使用上面提到的[[NSMutableArray new] addObject:nil]方法来强制关闭(崩溃)应用程序,而不会调用明显的exit(0)函数。
为什么?因为我的应用程序在所有网络API调用中使用证书固定来防止中间人攻击。这些包括我的金融应用程序在启动时进行的初始化调用。
如果证书认证失败,则所有的初始化调用都会出错,并使我的应用程序处于不确定状态。让用户回到主页然后再进入应用程序是无济于事的,因为除非应用程序已被操作系统清除,否则它仍然未初始化且不可信。
因此,在这种情况下,我们认为最好弹出警报通知用户应用程序正在以不安全的环境运行,然后当他们点击“关闭”时使用上述方法强制退出应用程序。

我看不出来为什么你不能显示一个全屏的普通警告,告诉用户应用程序由于“证书固定”原因无法使用,就这样。用户最终会关闭应用程序。也许你不知道,但iOS保留了杀死进程(保持其状态)并稍后恢复它的权利,“生命周期”不是真正掌握在你手中的iOS应用程序。你的崩溃只是一个崩溃,操作系统可能会选择重新启动应用程序。 - Motti Shneor
哇,这篇文章已经三年了。不管怎样,新的应用程序架构基本上就是这样做的,它有一个重试按钮,可以重试API并且要么取消阻塞屏幕,要么返回到阻塞屏幕并显示新的错误信息。 - Michael Long
旧的应用程序结构几乎没有好的方法来重试启动API调用,如果没有它们,该应用程序将处于不一致状态。我们本可以使用永久性阻止屏幕,但这需要用户自己强制退出应用程序,而且决定并非每个用户都知道如何双击和强制退出应用程序。今天更容易了,但在三年前相当隐蔽。 - Michael Long

1
[[UIApplication sharedApplication] terminateWithSuccess];

它运行良好并自动调用

- (void)applicationWillTerminateUIApplication *)application delegate.

为消除编译时警告,请添加此代码

@interface UIApplication(MyExtras)
  - (void)terminateWithSuccess;
@end 

5
这是一个私有方法,Diego Mercado已经解释过他的应用程序被拒绝了,为什么要冒这样的风险。 - RVN
使用私有API将会被苹果拒绝。 - ZYiOS
2
对于企业应用程序 - 这可以是一个解决方案。 - user1140780
  • (IBAction)exitApp:(id)sender { SEL selector = NSSelectorFromString(@"terminateWithSuccess"); [self performSelector:selector withObject:[UIApplication sharedApplication]]; }
(IBAction)exitApp:(id)sender { SEL选择器= NSSelectorFromString(@“terminateWithSuccess”); [self performSelector:selector withObject:[UIApplication sharedApplication]]; }
- unom
@unmircea 这个通过审核了吗? - Awesome-o

0

如果一个应用程序是长期运行的,并且还在后台执行,例如使用“位置更新”背景功能来获取位置更新,则退出应用程序可能是合适的。

例如,假设用户从您的基于位置的应用程序注销并使用主页按钮将应用程序推到后台。在这种情况下,您的应用程序可能仍在运行,但完全退出它可能是有意义的。这对用户有好处(释放不需要使用的内存和其他资源),对应用程序的稳定性也有好处(即确保在可能时定期重新启动应用程序是防止内存泄漏和其他低内存问题的安全网)。

这可以通过类似以下内容的方式实现(尽管可能不应该,请参见下文 :-):

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    if (/* logged out */) {
        exit(0);
    } else {
       // normal handling.
    }
}

由于应用程序将退出后台,因此对用户来说看起来不会出错,也不会像崩溃一样,只要下次运行应用程序时恢复用户界面即可。换句话说,当应用程序在后台运行时,对用户来说,它看起来与系统启动的终止应用程序没有任何区别。

尽管如此,最好使用更标准的方法让系统知道可以终止应用程序。例如,在这种情况下,通过确保GPS未被使用来停止请求位置更新,包括关闭地图视图上的显示当前位置。这样,系统将在应用程序进入后台后几分钟(即[[UIApplication sharedApplication] backgroundTimeRemaining])自动终止应用程序。这将获得所有相同的好处,而无需使用代码终止应用程序。

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    if (/* logged out */) {
       // stop requesting location updates if not already done so
       // tidy up as app will soon be terminated (run a background task using beginBackgroundTaskWithExpirationHandler if needed).
    } else {
       // normal handling.
    }
}

当然,对于在前台运行的普通生产应用程序来说,使用exit(0)是不合适的,这与其他参考http://developer.apple.com/iphone/library/qa/qa2008/qa1561.html的答案相符。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接