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

Proper way to exit iPhone application?

提问人:user21293 提问时间:12/10/2008 最后编辑:TheNeiluser21293 更新时间:4/1/2023 访问量:252881

问:

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

iOS Objective-C iPhone Cocoa-Touch iPad

评论

35赞 beryllium 2/21/2012
只有一种正确的方法 - 主页按钮。
5赞 Daniel 8/27/2012
我能想象到任何考虑以编程方式退出的人的唯一情况是以下情况:应用程序启动,显示使用条款,拒绝接受然后退出应用程序。这是品牌有时会向开发人员施加压力的事情。但这是错误的。
6赞 Paul de Lange 12/17/2012
@Daniel 通常,当您上传应用程序时,您会将免责声明/使用条款 (EULA) 放在 itunes connect 上。如果用户下载了你的应用,则表示他们已接受你的 EULA
9赞 badweasel 10/9/2013
需要强制退出 ios 应用程序是完全有正当理由的。我的情况是,我正在分发我的应用程序的发布前测试版。测试版免费开放所有IAP。这些有时间限制,需要在几周后到期。因此,我使用下面的答案在测试期结束后终止应用程序。我将在 LIVE 版本中删除它。但答案仍然帮助了我,而且是正确的!
6赞 frankodwyer 10/13/2015
退出应用的一个正当理由是,如果它是一个长期在后台执行的应用,并且该应用进入不再需要在后台运行的状态。例如,用户注销。在这种情况下,退出是有意义的,这样当应用程序下次启动时,它就会干净地开始。除其他原因外,这将充当防止内存泄漏的安全网。请注意,在这种情况下,应用程序将从后台退出,因此用户不会注意到任何错误。

答:

226赞 Brett 12/10/2008 #1

你试过吗?exit(0)

或者,虽然我没有尝试过,但它似乎是更合适的解决方案。[[NSThread mainThread] exit]

评论

85赞 Olie 12/19/2008
由于这样做是 Apple 的禁忌(可能会导致您的应用程序因非标准界面而在应用商店中被拒绝),因此请考虑 August 的答案为“正确的答案”。仅供参考,这个答案(Brett 的)对于所有 C 程序都是正确的,而 NSThread 对于所有 Cocoa 程序都是正确的。
22赞 progrmr 5/6/2010
在技术问答 QA1561 中,Apple 强烈建议不要使用退出,因为它会使应用程序看起来已经崩溃。developer.apple.com/iphone/library/qa/qa2008/qa1561.html
8赞 user123444555621 7/6/2010
[[NSThread mainThread] exit] 会导致应用程序崩溃,因为 exit 不是实例方法。exit(0) 会在 iOS 4 中将应用发送到后台。再次调用 exit(0) 将使其崩溃。至少在模拟器中。
14赞 evanflash 5/21/2013
我理解为什么这么多人建议不要这样做,但是给我们开发人员一些荣誉怎么样?我们都是成年人,我们想知道这个功能。我发现它对内部 QA 构建非常有用,当我第一次搜索它时,很高兴看到这个“不正确”的答案。
12赞 Glenn Maynard 5/25/2016
@Kevin“不要那样做”从来都不是正确的答案。如果您愿意,可以给出警告和免责声明,但“我该怎么做”的唯一正确答案是“这是如何做到的”。如果我正在寻找如何做某事(也许我想在调试时强制它退出),人们正义地宣称“你没有!”并试图掩盖我需要的答案是浪费我的时间。无论许多人可能有不好的理由去做某事,正确的 StackOverflow 答案就是回答这个问题的答案,因为有充分理由的人也会寻找它的方式。
2赞 Chris Jefferson 12/10/2008 #2

除了上面,很好,答案我只是想补充一下,想想清理你的记忆。

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

评论

0赞 rptwsthi 4/15/2011
请在IOS4.0及以上版本的当前场景下修改您的答案。:P
276赞 August 12/10/2008 #3

在 iPhone 上,没有退出应用程序的概念。导致应用程序退出的唯一操作是触摸手机上的主页按钮,而开发人员无法访问此功能。

根据 Apple 的说法,您的应用程序不应自行终止。由于用户没有点击主屏幕按钮,因此任何返回到主屏幕都会给用户留下应用崩溃的印象。这是令人困惑的非标准行为,应避免。

评论

13赞 August 12/11/2008
正如我所说,这是非标准行为,应该避免。iPhone 应用程序不是桌面应用程序。不要这样对待他们。
8赞 Anthony Main 1/26/2009
我可以理解苹果的意见,但我有类似的情况,我的应用程序需要互联网访问,如果它不可用,他们应该能够离开应用程序,而不仅仅是错误消息
25赞 JamesSugrue 5/10/2009
我们有帮助人们入睡的应用程序。他们希望应用程序在设定的时间段后终止,以减少电池消耗。我认为这种情况是可以接受的 - 因为用户希望已经睡着了,无法手动退出应用程序。
39赞 August 5/10/2009
我仍然不同意。当他们醒来时,应用程序已经“消失”,让用户想知道发生了什么。相反,在您的应用程序中设置一个计时器,然后在时间到时,将应用程序闲置 - 没有活动。一个完全不做任何事情的应用程序不会耗尽电池电量。Springboard 也是一个应用程序——它不会仅仅为了节省能源而关闭。相反,它只是等待用户输入。
9赞 Ben Zotto 9/20/2010
这并不能真正回答这个问题。它是 100% 准确的,但我认为理想情况下是对 OP 的问题或公认的答案的评论。
3赞 Rob 12/11/2008 #4

嗯,如果您的应用程序需要互联网连接,您可能“不得不”退出应用程序。您可以显示警报,然后执行如下操作:

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

评论

9赞 August 12/11/2008
不,您不必终止它。例如,当iTunes应用程序无法检测到正确的连接时,它只会显示一个屏幕,显示它们未连接。它不会退出,它只是通知用户正在发生的事情。然后,用户通过点击主页按钮退出。
1赞 Josh Lee 11/5/2009
但是,如果指南针应用程序无法运行,它就会退出。
13赞 Romain Champourlier 5/18/2009 #5

经过一些测试,我可以说以下几点:

  • 使用私有接口:将导致应用程序看起来像崩溃,但它会在这样做之前调用;[UIApplication sharedApplication]- (void)applicationWillTerminate:(UIApplication *)application
  • using 也会终止应用程序,但它看起来“正常”(跳板的图标按预期显示,带有缩小效果),但它不会调用委托方法。exit(0);- (void)applicationWillTerminate:(UIApplication *)application

我的建议:

  1. 手动调用 on 委托。- (void)applicationWillTerminate:(UIApplication *)application
  2. 叫。exit(0);

评论

0赞 9/6/2012
苹果表示不使用退出,因为“调用退出的应用程序将向用户显示已经崩溃,而不是执行优雅终止并动画返回主屏幕”developer.apple.com/library/ios/#qa/qa2008/qa1561.html
38赞 cwe7976 8/4/2009 #6

这并不是一种退出程序的方法,而是一种迫使人们退出的方式。

UIAlertView *anAlert = [[UIAlertView alloc] initWithTitle:@"Hit Home Button to Exit" message:@"Tell em why they're quiting" delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
[anAlert show];

评论

2赞 cheshirekow 8/31/2012
至少在模拟器上,如果执行此操作,当用户重新打开应用时,警报仍将存在。因此,我建议至少给他们一个按钮。
0赞 Timur Kuchkarov 2/19/2013
使用 Kalyan 的答案,以便在按下主页按钮时应用程序退出。
0赞 Ky - 6/24/2015
这样做的问题在于它实际上并没有退出应用程序,因此除非用户关闭应用程序,否则开发人员可能希望通过退出(抛出无效/旧的 UI、清除常量等)来完成的任何事情都不会执行。
0赞 Dustin 12/5/2015
这不会终止应用程序。
1赞 shiva 11/5/2009 #7
[[UIApplication sharedApplication] terminateWithSuccess];

它工作正常并自动调用

- (void)applicationWillTerminateUIApplication *)application delegate.

若要删除编译时警告,请添加以下代码

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

评论

5赞 RVN 10/15/2010
这是一种私人方法,迭戈·梅尔卡多(Diego Mercado)在上面解释过,他的应用程序被拒绝了,那为什么要冒这样的风险。
0赞 ZYiOS 11/20/2012
使用私有 API 将使应用程序被 Apple 拒绝。
2赞 user1140780 3/26/2013
对于企业应用程序 - 这可能是一个解决方案。
0赞 unom 10/1/2014
- (IBAction)exitApp:(id)sender { SEL selector = NSSelectorFromString(@“terminateWithSuccess”);[self performSelector:selector withObject:[UIApplication sharedApplication]];}
0赞 Awesome-o 4/19/2016
@unmircea通过了审查?
6赞 user223106 12/3/2009 #8

我的应用程序最近被拒绝了,因为我使用了未记录的方法。按照字面:

“不幸的是,它无法添加到App Store,因为它使用的是私有API。禁止使用非公开 API,如《iPhone Developer Program 许可协议》第 3.3.1 节所述:

“3.3.1 应用程序只能按照 Apple 规定的方式使用记录在案的 API,不得使用或调用任何私有 API。”

应用程序中包含的非公共 API 是 terminateWithSuccess”

41赞 Wagh 6/5/2010 #9

在此处查看问答:https://developer.apple.com/library/content/qa/qa1561/_index.html

问:如何以编程方式退出 iOS 应用程序?

没有提供用于正常终止 iOS 应用程序的 API。

在 iOS 中,用户按“主页”按钮关闭应用程序。如果您的应用程序存在无法提供其预期功能的情况,建议的方法是向用户显示警报,指示问题的性质以及用户可以采取的可能操作 - 打开 WiFi、启用定位服务等。允许用户自行决定终止应用程序。

警告:不要调用该函数。应用程序调用将向用户显示已崩溃,而不是执行正常终止并以动画形式返回主屏幕。exitexit

此外,可能无法保存数据,因为如果调用 exit,则不会调用类似的方法。-applicationWillTerminate:UIApplicationDelegate

如果在开发或测试期间需要终止应用程序,建议使用函数或宏abortassert

评论

2赞 Schultz9999 9/9/2013
只是添加了一个没有按钮的 AlertView 来满足这一点。容易。
0赞 Alex Cio 5/11/2017
很好的答案,刚刚使用 exit(0) 并且不知道它属于私有 api
9赞 L'g 8/12/2010 #10

ApplicationDelegate 收到用户有意退出的通知:

- (void)applicationWillResignActive:(UIApplication *)application {

当我收到此通知时,我只是打电话

        exit(0);

它完成了所有的工作。最好的事情是,这是用户退出的意图,这就是为什么在那里调用它应该不是问题。

在我的音频应用程序上,在人们在音乐仍在播放时同步他们的设备后,有必要退出该应用程序。同步完成后,我会收到通知。但是在那之后立即退出应用程序实际上看起来像是崩溃。

因此,我设置了一个标志,以便在下一个后台操作时真正退出应用程序。这对于在同步后刷新应用程序是可以的。

评论

1赞 frankodwyer 10/13/2015
这不是一个好的解决方案,因为应用程序将因其他原因(例如来电)而退出活动状态。
0赞 cat 8/31/2018
解决方案是添加一个检查,只有在有用时才退出。例如,如果用户位于“开始”屏幕上。然后,即使有电话打进来也没关系。自 iOS 2 以来,Apple 在我的应用程序中没有拒绝过这一点。 stackoverflow.com/a/43906936/712124
4赞 nanonyme 2/3/2011 #11

这已经得到了一个很好的答案,但决定扩展一下:

如果不仔细阅读 Apple 的 iOS 人机界面指南,您就无法让您的应用程序被 AppStore 接受。(他们保留拒绝您对他们做任何事情的权利)http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices.html“不要以编程方式戒烟”部分是在这种情况下应如何治疗的确切指南。

如果您在使用Apple平台时遇到问题,无法轻松找到解决方案,请咨询HIG。苹果可能根本不希望你这样做,他们通常(我不是苹果,所以我不能保证总是)在他们的文档中这么说。

37赞 Kalyan 6/1/2011 #12

转到您的 info.plist 并检查“应用程序不在后台运行”键。这一次,当用户单击主页按钮时,应用程序将完全退出。

评论

1赞 Gajendra K Chauhan 7/9/2013
但后台进程也会被解雇。
17赞 Aman Agarwal 7/7/2011 #13

将属性添加到 。UIApplicationExitsOnSuspendapplication-info.plisttrue

评论

0赞 Motti Shneor 3/13/2019
是否可以在运行时更改此设置?我的意思是,我想在后台运行,除非我的应用程序选择在下一次挂起时退出 - 此时我将要引入 UIApplicationExitsOnSuspend。这可能吗?
6赞 AGPX 5/23/2013 #14

苹果说:

“警告:不要调用退出函数。调用退出的应用程序将向用户显示已崩溃,而不是执行正常终止并以动画形式返回主屏幕。

我认为这是一个糟糕的假设。如果用户点击退出按钮并显示一条消息,内容如下:“应用程序现在将退出”,则它似乎不会崩溃。Apple 应提供退出应用程序的有效方法(而不是 exit(0))。

评论

3赞 Popeye 5/23/2013
他们这样做,它被称为主页按钮,它可以位于任何iDevice的底部。因此,正因为如此,永远不需要构建自己的退出按钮。
51赞 MD SHAHIDUL ISLAM 7/23/2013 #15

exit(0)在用户看来是崩溃,因此请向用户显示确认消息。确认后暂停(以编程方式按下主页按钮)并等待 2 秒钟,同时应用程序进入后台并显示动画,然后在用户视图后面退出

-(IBAction)doExit
{
    //show confirmation message to user
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Confirmation"
                                                 message:@"Do you want to exit?"
                                                delegate:self
                                       cancelButtonTitle:@"Cancel"
                                       otherButtonTitles:@"OK", nil];
    [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
        exit(0);
    }
}

评论

1赞 Gajendra K Chauhan 1/24/2014
苹果会批准这个“exit(0)”吗?因为有人说,当你使用exit 0时,苹果会拒绝你的应用。
2赞 eonil 2/3/2016
@GajendraKChauhan并不重要。关键是你的应用有“退出行为”。AppStore 中禁止退出行为本身,但少数由非常重要的第三方制作的应用程序除外。此外,模仿主页按钮的行为也会被拒绝。exit(0)
2赞 Prabhu Natarajan 9/17/2013 #16
- (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);
  }
}
0赞 Binarian 9/30/2013 #17

用户应决定应用何时退出。 我不认为当应用程序退出时,这不是一个好的用户交互。因此,它没有很好的 API,只有主页按钮有一个。

如果出现错误:更好地实现或通知用户。 如果必须重新启动:最好实现通知用户。

这听起来很愚蠢,但在不让用户决定且不通知他的情况下退出应用程序是一种不好的做法。苹果公司表示,由于有一个用于用户交互的主页按钮,因此同一功能(退出应用程序)不应该有两件事。

0赞 Geri Borbás 1/27/2014 #18

退出应用程序而不是主页按钮确实是非 iOS 式的方法。

不过,我做了这个不使用私人东西的帮手:

void crash()
{ [[NSMutableArray new] addObject:NSStringFromClass(nil)]; }

但在我的情况下仍然不适合生产。它用于测试崩溃报告,或在核心数据重置后快速重启。只是如果功能留在生产代码中,就不会被拒绝。

0赞 frankodwyer 10/13/2015 #19

如果应用是长期运行的应用,并且也在后台执行,则退出应用可能是合适的,例如获取位置更新(使用位置更新后台功能)。

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

这可能(虽然可能不应该,见下文:-)通过以下方式实现:

- (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.
    }
}

当然,使用永远不适合在前台运行的普通生产应用程序,因为根据引用 http://developer.apple.com/iphone/library/qa/qa2008/qa1561.html 的其他答案exit(0)

1赞 Michael Long 11/25/2015 #20

我使用上面提到的 [[NSMutableArray new] addObject:nil] 方法来强制退出(崩溃)应用程序,而无需进行明显的 exit(0) 函数调用。

为什么?因为我的应用在所有网络 API 调用上使用证书固定来防止中间人攻击。其中包括我的金融应用程序在启动时进行的初始化调用。

如果证书身份验证失败,我的所有初始化调用都会出错,并使我的应用处于不确定状态。让用户回家然后返回应用无济于事,因为除非应用已作系统清除,否则它仍然未初始化且不可信。

因此,在这种情况下,我们认为最好弹出警报,通知用户应用程序在不安全的环境中运行,然后,当他们点击“关闭”时,使用上述方法强制退出应用程序。

评论

0赞 Motti Shneor 3/13/2019
我看不出是什么阻止你显示一个全屏平凡的警报,告诉用户由于那些“证书固定”原因,该应用程序不可用,仅此而已。用户最终将关闭应用程序。你可能不知道,但iOS保留终止你的进程(保持其状态)并在以后恢复它的权利,iOS应用程序的“生命周期”并不真正掌握在你手中。您的崩溃 - 只是崩溃,操作系统可能会选择恢复应用程序。
0赞 Michael Long 3/15/2019
哇,三年前的帖子。无论如何,新的应用程序架构几乎可以做到这一点,使用重试按钮重试 API 并丢弃阻止屏幕,或者将它们返回到阻止屏幕并出现新错误。
0赞 Michael Long 3/15/2019
旧的应用程序结构几乎不允许任何好的方法来重试启动 API 调用,并且没有它们,应用程序处于不一致的状态。我们可以使用永久阻止屏幕,但这需要用户自己强制退出应用程序,并且决定并非每个用户都知道如何双击并强制退出应用程序。今天更容易,但在三年前却很隐蔽。
3赞 technerd 4/28/2016 #21

我们不能退出使用、功能的应用程序,因为 Apple 强烈建议不要使用这些功能。虽然您可以将此功能用于开发或测试目的。exit(0)abort()

如果在开发或测试期间有必要终止 建议使用 application、abort 函数或 assert 宏

请找到这个 Apple Q&A 主题以获取更多信息。

由于使用此功能会给人留下应用程序崩溃的印象。所以我得到了一些建议,例如由于某些功能不可用,我们可以显示带有终止消息的警报,以告知用户关闭应用程序。

但是iOS人机界面指南启动和停止应用程序,建议永远不要使用退出或关闭按钮来终止应用程序。相反,他们建议显示适当的信息来解释情况。

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

切勿以编程方式退出 iOS 应用。人们倾向于解释这一点 作为崩溃。如果某些原因阻止您的应用以 有意,您需要告诉用户情况并解释什么 他们可以做到这一点。

0赞 Saranjith 2/28/2019 #22

Swift 4.2(或更早版本)

可以使用调用的库。Darvin

import Darwin

exit(0) // Here you go

注意:这在 iOS 应用程序中是不推荐的。

这样做会让你看到崩溃日志。

5赞 TheTiger 6/18/2019 #23

不应直接调用该函数,因为它会立即退出应用程序,并且看起来应用程序已崩溃。因此,最好向用户显示确认警报,让他们自己执行此操作。exit(0)

斯威夫特 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()
     }
}
0赞 Klaas 11/22/2019 #24

在 iPadOS 13 中,您现在可以关闭所有场景会话,如下所示:

for session in UIApplication.shared.openSessions {
    UIApplication.shared.requestSceneSessionDestruction(session, options: nil, errorHandler: nil)
}

这将调用您的应用委托并最终终止应用。applicationWillTerminate(_ application: UIApplication)

但要注意两件事:

有关 iOS/iPadOS 13 中的场景的详细信息:https://developer.apple.com/documentation/uikit/app_and_environment/scenes