【问题标题】:Proper way to exit iPhone application?退出 iPhone 应用程序的正确方法?
【发布时间】:2010-09-26 04:36:05
【问题描述】:

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

【问题讨论】:

  • 只有一种正确的方式 - 主页按钮..
  • 我能想象到的任何人考虑以编程方式退出的唯一情况是以下情况:应用程序启动,显示使用条款,拒绝接受然后退出应用程序。这是品牌有时会迫使开发商做的事情。但这是错误的。
  • @Daniel 通常,您在上传应用程序时会将免责声明/使用条款 (EULA) 放在 iTunes Connect 上。如果用户下载您的应用,则表示他们已接受您的 EULA
  • 有完全正当的理由需要强制退出 ios 应用程序。我的情况是我正在分发我的应用程序的发布前测试版。测试版免费开放所有 IAP。这些有时间限制,需要在几周后到期。所以我在测试期结束后使用下面的答案来杀死应用程序。我将在 LIVE 版本中删除它。但是答案仍然对我有所帮助并且是正确的!
  • 退出应用程序的一个正当理由是,如果它是一个长期存在的后台执行应用程序,并且应用程序进入不再需要在后台运行的状态。例如,用户注销。在这种情况下,退出是有意义的,这样当应用程序下次启动时它就会开始干净。除其他原因外,这将作为防止内存泄漏的安全网。请注意,在这种情况下,应用程序将退出后台,因此用户不会注意到任何错误。

标签: ios objective-c iphone cocoa-touch ipad


【解决方案1】:

在 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

【讨论】:

    【解决方案2】:

    你不应该直接调用函数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()
         }
    }
    

    【讨论】:

      【解决方案3】:

      application-info.plist 上的UIApplicationExitsOnSuspend 属性添加到true

      【讨论】:

      • 可以在运行时更改此设置吗?我的意思是,我想在后台运行,除非我的应用程序选择在下一次暂停时退出——此时我将要介绍 UIApplicationExitsOnSuspend。这可能吗?
      【解决方案4】:

      Swift 4.2(或更早版本)

      可以使用名为Darvin 的库。

      import Darwin
      
      exit(0) // Here you go
      

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

      这样做会得到崩溃日志。

      【讨论】:

        【解决方案5】:

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

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

        没有提供用于优雅终止 iOS 应用程序的 API。

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

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

        另外,可能不会保存数据,因为如果您调用 exit,将不会调用 -applicationWillTerminate: 和类似的 UIApplicationDelegate 方法。

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

        【讨论】:

        • 刚刚添加了一个没有按钮的 AlertView 来遵守这一点。容易。
        • 很好的答案,刚刚使用 exit(0) 并且不知道它属于私有 api
        【解决方案6】:
        [[UIApplication sharedApplication] terminateWithSuccess];
        

        它工作正常并自动调用

        - (void)applicationWillTerminateUIApplication *)application delegate.
        

        要删除编译时警告添加此代码

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

        【讨论】:

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

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

        如果在开发或测试期间有必要终止您的 建议使用应用程序、中止函数或断言宏

        请查找此 Apple Q&A 线程以获取更多信息。

        使用此功能会产生应用程序崩溃的印象。所以我得到了一些建议,比如我们可以向意识到用户关闭应用程序的终止消息显示警报,因为某些功能不可用。

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

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

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

        【讨论】:

          【解决方案8】:

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

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

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

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

          【讨论】:

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

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

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

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

          - (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) 永远不适合在前台运行的普通生产应用程序

          【讨论】:

            【解决方案10】:
            - (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);
              }
            }
            

            【讨论】:

              【解决方案11】:

              以除主页按钮之外的其他方式退出应用是真正非 iOS 风格的方法。

              不过,我做了这个助手,它不使用任何私人的东西:

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

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

              【讨论】:

                【解决方案12】:

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

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

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

                【讨论】:

                  【解决方案13】:

                  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);
                      }
                  }
                  

                  【讨论】:

                  • 苹果会批准这个“exit(0)”吗?因为有人说当你使用 exit 0 时苹果会拒绝你的应用。
                  • @GajendraKChauhan exit(0) 没关系。重点是您的应用程序具有“退出行为”。退出行为本身在 AppStore 中是被禁止的,除了一些非常重要的第三方制作的应用程序。另外,模仿home键的行为也会被拒绝。
                  【解决方案14】:

                  苹果说:

                  “警告:不要调用退出函数。调用退出的应用程序在用户看来已经崩溃,而不是执行正常终止并动画返回主屏幕。”

                  我认为这是一个糟糕的假设。如果用户点击退出按钮并出现一条消息,例如:“应用程序现在将退出。”,它似乎没有崩溃。 Apple 应该提供一种有效的方式来退出应用程序(而不是 exit(0))。

                  【讨论】:

                  • 他们称之为 Home 按钮,它可以位于任何 iDevice 的底部。因此,因此永远不需要在其中构建自己的退出按钮。
                  【解决方案15】:

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

                  【讨论】:

                  • 但后台进程也会被解雇。
                  【解决方案16】:

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

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

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

                  【讨论】:

                    【解决方案17】:

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

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

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

                            exit(0);
                    

                    所有的工作都由它完成。最好的是,用户打算退出,这就是为什么在那儿调用它应该不是问题。

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

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

                    【讨论】:

                    • 这不是一个好的解决方案,因为应用程序将因其他原因退出活动状态,例如来电。
                    • 解决方案是添加一个仅在有用时才退出的检查。例如,如果用户在开始屏幕上。然后,即使有电话打进来也没关系。自从我的应用程序中的 iOS 2 以来,Apple 并没有拒绝这一点。 stackoverflow.com/a/43906936/712124
                    【解决方案18】:

                    你试过exit(0)吗?

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

                    【讨论】:

                    • 因为这样做是 Apple 的禁忌(可能会导致您的应用在非标准界面的应用商店中被拒绝),因此将 August 的回答视为“正确的”。仅供参考,这个答案(Brett's)对于所有 C 程序都是正确的,对于所有 Cocoa 程序都是正确的。
                    • 在技术问答 QA1561 中,Apple 强烈反对使用退出,因为它会使应用程序看起来已经崩溃。 developer.apple.com/iphone/library/qa/qa2008/qa1561.html
                    • [[NSThread mainThread] exit] 会导致您的应用程序崩溃,因为 exit 不是实例方法。 exit(0) 会将应用程序发送到 iOS 4 的后台。再次调用 exit(0) 将使其崩溃。至少在模拟器中。
                    • 我明白为什么这么多人反对这个,但是给我们开发者一些信任怎么样?我们都是成年人,我们想知道这个功能。我发现它对于内部 QA 构建非常有用,当我第一次搜索它时,很高兴看到这个“不正确”的答案。
                    • @Kevin “不要那样做”永远不是正确的答案。如果您愿意,请提供警告和免责声明,但“我该怎么做”的唯一正确答案是“这是怎么做的”。如果我正在寻找如何做某事(也许我想在调试时强制它退出),人们会正确地声明“你没有!”试图掩盖我需要的答案是在浪费我的时间。不管很多人做某事可能有不好的理由,正确的 StackOverflow 答案就是回答这个问题的答案,因为有充分理由的人也会寻找解决问题的方法。
                    【解决方案19】:

                    我的应用最近被拒绝,因为我使用了一种未记录的方法。字面意思:

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

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

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

                    【讨论】:

                      【解决方案20】:

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

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

                      【讨论】:

                      • 至少在模拟器上,如果你这样做,当用户重新打开应用程序时,警报仍然存在。因此,我建议给他们至少一个按钮。
                      • 使用 Kalyan 的答案,以便在按下主页按钮时退出应用程序。
                      • 这个问题是它实际上并没有退出应用程序,因此开发人员可能想要通过退出来完成的任何事情(抛出无效/旧 UI、清除常量等)都不会除非用户滑动关闭应用程序,否则执行。
                      • 这不会杀死应用程序。
                      【解决方案21】:

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

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

                      我的建议:

                      1. 手动调用代理上的- (void)applicationWillTerminate:(UIApplication *)application
                      2. 致电exit(0);

                      【讨论】:

                      【解决方案22】:

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

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

                      【讨论】:

                      • 不,您不必终止它。例如,当 iTunes 应用程序无法检测到正确的连接时,它只会显示一个屏幕,显示它们未连接。它不会退出,它只是通知用户正在发生的事情。然后用户通过点击主页按钮退出。
                      • 如果指南针应用程序无法运行,它将退出。
                      【解决方案23】:

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

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

                      【讨论】:

                      • 正如我所说,这是非标准行为,应该避免。 iPhone 应用程序不是桌面应用程序。不要这样对待他们。
                      • 我能理解苹果的意见,但我也有类似的情况,我的应用程序需要互联网访问,如果它不可用,他们应该能够离开应用程序,而不仅仅是出现错误消息
                      • 我们有帮助人们睡眠的应用程序。他们希望应用程序在一段时间后终止,以减少电池消耗。我认为这种情况是可以接受的——因为希望用户睡着了,不能手动退出应用程序。
                      • 我还是不同意。当他们醒来时,应用程序“消失”了,让用户想知道发生了什么。相反,在你的应用程序中设置一个计时器,然后当时间到了,让应用程序空闲——没有活动。一个完全不做任何事情的应用程序不会耗尽电池。Springboard 也是一个应用程序——它不会仅仅为了节省能源而关闭。相反,它只是等待用户输入。
                      • 这并不能真正回答问题。它是 100% 准确的,但我认为理想情况下应该是对 OP 的问题或已接受的答案的评论。
                      【解决方案24】:

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

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

                      【讨论】:

                      • 请在IOS4.0和UP的当前场景下修改你的答案..:P
                      猜你喜欢
                      • 2016-11-12
                      • 1970-01-01
                      • 2011-12-22
                      • 2016-11-23
                      • 2012-01-03
                      • 2016-05-25
                      • 2016-06-05
                      • 1970-01-01
                      相关资源
                      最近更新 更多