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


277

我正在编写iPhone应用程序,由于某些用户操作,我需要强制其退出。清理分配给应用程序的内存后,调用哪种方法终止应用程序?


34
只有一种正确的方式- Home键..

5
我能想象的任何人考虑以编程方式退出的情况是以下情形:应用程序启动,显示使用条款,拒绝接受然后退出应用程序。品牌有时会向开发人员施加压力。但这是错误的。
丹尼尔(Daniel)

6
@Daniel通常,您在上载应用程序时会在iTunes Connect上放置免责声明/使用条款(EULA)。如果用户下载了您的应用,则表示他们已接受您的EULA
Paul de Lange

8
有完全有效的理由需要强制退出ios应用。我的情况是我正在分发应用程序的预发布Beta版本。Beta版免费开放所有IAP。这些有时间限制,需要在几周后过期。因此,我使用下面的答案在Beta测试期结束后终止了该应用程序。我将在LIVE版本中删除它。但是答案仍然对我有帮助,而且是正确的!
badweasel,

5
退出应用程序的一个有效原因是,如果该应用程序是长期运行的后台执行应用程序,并且该应用程序进入一种不再需要在后台运行的状态。例如,用户注销。在这种情况下,退出是有意义的,以便下次启动应用程序时它开始干净。除其他原因外,这将作为防止内存泄漏的安全网。请注意,在这种情况下,该应用将退出后台运行,因此用户不会注意到任何错误。
frankodwyer 2015年

Answers:


217

你试过了exit(0)吗?

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


85
由于这是Apple的禁忌措施(可能会导致您的应用程序因非标准界面而在应用商店中被拒绝),因此应将August的答案视为“正确的选择”。仅供参考,此答案(布雷特)适用于所有C程序,适用于所有可可程序的NSThread。
OLIE

21
在Tech Q&A QA1561中,Apple强烈不鼓励使用exit,因为它使应用程序看起来已经崩溃。 developer.apple.com/iphone/library/qa/qa2008/qa1561.html
progrmr 2010年

8
[[NSThread mainThread] exit]导致您的应用程序崩溃,因为exit不是实例方法。exit(0)会将应用程序发送到iOS 4中的后台。再次调用exit(0)将其崩溃。至少在模拟器中。
user123444555621 2010年

10
我理解为什么有这么多人建议这样做,但是如何给我们开发人员一些信誉呢?我们都是成年人,我们想知道这个功能。我发现它对于内部质量检查构建非常有用,当我第一次搜索它时,很高兴看到这个“错误”的答案。
evanflash 2013年

7
@Kevin“不要那样做”永远不是正确的答案。如果愿意,请给出警告和免责声明,但是“我该怎么做”的唯一正确答案是“这是怎么做”。如果我正在寻找如何做某事(也许我想在调试时强制其退出),那么人们会正确地宣布“您不要!”。试图掩盖我需要的答案是在浪费时间。但是,许多人可能有不好的理由去做某事,正确的StackOverflow答案就是回答该问题的答案,因为有充分理由的人也会寻找解决方法。
格伦·梅纳德

274

在iPhone上,没有退出应用程序的概念。导致应用程序退出的唯一动作是触摸手机上的“主页”按钮,而这不是开发人员可以访问的。

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


13
正如我所说,这是非标准行为,应避免使用。iPhone应用程序不是桌面应用程序。不要这样对待他们。
8

8
我可以理解苹果的意见,但我的情况与此类似,我的应用程序需要访问互联网,如果无法访问,他们应该可以离开应用程序而不仅仅是收到错误消息
Anthony Main 2009年

22
我们有可以帮助人们入睡的应用程序。他们希望应用程序在设定的时间段后终止,以减少电池消耗。我认为这种情况是可以接受的-因为用户希望睡着并且无法手动退出应用程序。
JamesSugrue,2009年

36
我还是不同意。当他们醒来时,该应用程序“消失了”,让用户怀疑发生了什么。相反,请在您的应用程序中设置一个计时器,然后在时间到时使应用程序处于空闲状态-无需进行任何操作。绝对不执行任何操作的应用程序都不会耗尽电池.Springboard也是一个应用程序-它不会为了节省能源而关闭。相反,它只是等待用户输入。
8

8
这并不能真正回答问题。这是100%准确的,但我认为理想情况下,无论是对OP的问题还是对公认的答案,都应该是一条评论。
Ben Zotto

49

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
苹果会批准此“退出(0)”吗?因为有些人说,当你使用退出0苹果将拒绝您的应用程序
加金德拉ķ肖汉

2
@GajendraKChauhan exit(0)没关系。重点是您的应用程序具有“退出行为”。除了非常重要的第三方制作的一些应用程序外,AppStore本身也禁止退出行为。同样,模仿主页按钮的行为也将被拒绝。
Eonil '16

41

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

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

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

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

警告:请勿调用该exit函数。exit在用户看来,应用程序调用将崩溃,而不是执行正常的终止并动画返回主屏幕。

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

如果在开发或测试期间有必要终止应用程序,则建议使用abort函数或assert


2
刚刚添加了一个不带按钮的AlertView来遵守此规定。简单。
Schultz9999

很好的答案,只是与exit(0)一起使用,并且不知道它属于私有api
Alex Cio

39

它并不是退出程序的真正方法,而是迫使人们退出的方法。

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,2012年

使用Kalyan的答案,以便在按下主屏幕按钮时退出应用。
Timur Kuchkarov

问题在于它实际上并没有退出应用程序,因此除非用户滑动应用程序,否则开发人员可能想要通过退出(抛出无效/旧的UI,清除常量等)来完成的任何操作都不会执行。关闭。
Ben Leggiero

这不会杀死应用程序。
达斯汀

38

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


1
但是后台进程也被解雇了。
Gajendra K Chauhan

17

UIApplicationExitsOnSuspend属性添加application-info.plisttrue


可以在运行时更改此设置吗?我的意思是,我希望生活在后台,但当我的应用选择在下一个暂停状态退出时–这次我要介绍UIApplicationExitsOnSuspend。这可能吗?
Motti Shneor

13

经过一些测试,我可以说以下内容:

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

我的建议:

  1. 手动呼叫 - (void)applicationWillTerminate:(UIApplication *)application代理。
  2. 致电exit(0);

苹果表示,不使用退出原因是“应用程序调用exit将出现在用户已经崩溃,而不是执行正常终止和动画返回到主屏幕” developer.apple.com/library/ios/#qa/qa2008/ qa1561.html
MickyD 2012年

8

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

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

收到此通知后,我只打电话给

        exit(0);

哪个工作全部完成。最好的是,这是用户退出的意图,这就是为什么在此调用它应该不是问题。

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

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


1
这不是一个好的解决方案,因为该应用程序会由于其他原因(例如来电)而退出活动状态。
frankodwyer 2015年

解决方案是添加仅在有用时才退出的检查。例如,如果用户在开始屏幕上。这样就算打来电话也没关系。自我的应用程序中的iOS 2以来,Apple一直没有拒绝。stackoverflow.com/a/43906936/712124

6

我的应用最近被拒绝了,因为我使用了未公开的方法。从字面上看:

“很遗憾,由于它使用的是私有API,因此无法添加到App Store。禁止使用非公共API,如iPhone开发者计划许可协议第3.3.1节所述:

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

您的应用程序中包含的非公共API是TerminateWithSuccess“


6

苹果说:

“警告:请勿调用exit函数。调用exit的应用程序将对用户显示为已崩溃,而不是执行正常的终止并动画返回主屏幕。”

我认为这是一个错误的假设。如果用户点击退出按钮,然后出现一条消息,内容为:“应用程序现在将退出。”,则它似乎没有崩溃。Apple应该提供一种退出应用程序的有效方法(而不是exit(0))。


3
他们将其称为“主页”按钮,它可以位于任何iDevice的底部。因此,因此不再需要构建自己的退出按钮
。– Popeye

4

这已经得到了很好的答案,但是决定扩大一点:

您必须很好地阅读Apple的iOS人机界面指南,才能使您的应用程序被AppStore接受。(他们保留拒绝您对他们采取任何行动的权利)“请勿以编程方式退出”部分http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices。 html 是在这种情况下应如何处理的确切指南。

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


3

嗯,例如,如果您的应用程序需要Internet连接,则您可能“必须”退出该应用程序。您可以显示警报,然后执行以下操作:

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

9
不,您不必终止它。例如,当iTunes应用程序无法检测到正确的连接时,只需在屏幕上显示未连接的屏幕。它不会退出,它只是告诉用户发生了什么事。然后,用户通过点击主页按钮退出。
8

1
但是,如果指南针应用程序无法运行,则将其退出。
Josh Lee,2009年

3

我们不能退出应用程序中使用exit(0)abort()功能,苹果公司强烈反对使用这些功能。虽然您可以将此功能用于开发或测试目的。

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

请找到此Apple 问答线程以获取更多信息。

使用此功能后,会产生像应用程序崩溃的印象。因此,我得到了一些建议,例如由于某些功能不可用,我们可以显示带有终止消息的警报,以通知用户有关关闭该应用程序的信息。

但是iOS用于启动和停止应用程序的 iOS人机界面指南建议不要使用“退出”或“关闭”按钮来终止应用程序。相反,他们建议显示适当的消息以说明情况。

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

切勿以编程方式退出iOS应用。人们倾向于将其解释为崩溃。如果由于某种原因导致您的应用无法正常运行,则需要告知用户有关情况,并说明他们可以采取的措施。


2

除了上述内容外,我还想补充一下好答案,请考虑清理内存。

应用程序退出后,iPhone OS会自动清理您的应用程序留下的所有内容,因此手动释放所有内存只会增加应用程序退出所花费的时间。


请修改您在IOS4.0及以上版本的当前情况下的答案。:P
rptwsthi 2011年

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将使该应用程序被Apple拒绝。
ZYiOS 2012年

2
对于企业应用程序-这可以是一个解决方案。
user1140780 2013年

-(IBAction)exitApp:(id)sender {SEL选择器= NSSelectorFromString(@“ terminateWithSuccess”); [self performSelector:selector withObject:[UIApplication sharedApplication]]; }
unom 2014年

@unmircea通过了评论吗?
Awesome-o

1

您不应该直接调用该函数 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

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

如果有错误:请更好地实施或通知用户。如果必须重新启动:更好地实施“通知用户”。

这听起来很愚蠢,但是在不让用户决定并通知他的情况下退出应用程序是不明智的做法。Apple指出,由于有一个用于用户交互的主页按钮,因此对于同一功能(退出应用程序)不应有两件事。


0

除了主页按钮以外的其他方式退出应用程序,这实际上不是iOS风格的方法。

不过,我做了这个帮手,没有使用任何私人物品:

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

但就我而言,这仍然不适合生产。它用于测试崩溃报告,或在重置核心数据后快速重启。只是为了确保不遗漏生产代码中的功能,这是安全的。


0

Swift 4.2(或更旧版本)

Darvin可以使用称为库。

import Darwin

exit(0) // Here you go

注意:在iOS应用程序中不建议这样做。

这样做会导致崩溃日志。


0

在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


-1

以其他方式退出应用

不过,我做了这个帮手,没有使用任何私人物品:

退出(0);


-1

如果应用程序是一个寿命很长的应用程序,并且该应用程序也在后台执行,则可能适合退出该应用程序,例如获取位置更新(为此使用位置更新后台功能)。

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

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

- (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的其他答案,使用永远不会适合在前台运行的普通生产应用程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.