iPhoneアプリをプログラミングしていますが、特定のユーザーアクションのためにアプリを強制的に終了する必要があります。アプリが割り当てたメモリをクリーンアップした後、アプリケーションを終了するために呼び出す適切なメソッドは何ですか?
iPhoneアプリをプログラミングしていますが、特定のユーザーアクションのためにアプリを強制的に終了する必要があります。アプリが割り当てたメモリをクリーンアップした後、アプリケーションを終了するために呼び出す適切なメソッドは何ですか?
回答:
試しましたexit(0)
か?
または、[[NSThread mainThread] exit]
私は試していませんが、より適切な解決策のようです。
iPhoneでは、アプリを終了するという概念はありません。アプリを終了させる唯一のアクションは、電話のホームボタンをタッチすることであり、これは開発者がアクセスできるものではありません。
Appleによると、アプリはそれ自体で終了するべきではありません。ユーザーがホームボタンを押さなかったため、ホーム画面に戻ると、アプリがクラッシュしたような印象をユーザーに与えます。これは混乱を招く非標準的な動作であり、回避する必要があります。
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)
は関係ありません。ポイントは、アプリに「終了動作」があることです。AppStoreでは、非常に重要なサードパーティによって作成されたいくつかのアプリを除いて、動作自体を終了することは禁止されています。また、ホームボタンの動作の模倣も拒否される可能性があります。
こちらのQ&Aを確認してください:https : //developer.apple.com/library/content/qa/qa1561/_index.html
Q:iOSアプリケーションをプログラムで終了するにはどうすればよいですか?
iOSアプリケーションを適切に終了するためのAPIは提供されていません。
iOSでは、ユーザーはホームボタンを押してアプリケーションを閉じます。アプリケーションに目的の機能を提供できない状況が発生した場合、推奨されるアプローチは、問題の性質とユーザーが実行できる可能なアクション(WiFiのオン、位置情報サービスの有効化など)を示すアラートをユーザーに表示することです。ユーザーが自分の裁量でアプリケーションを終了できるようにします。
警告:
exit
関数を呼び出さないでください。アプリケーションの呼び出しexit
は、正常な終了を実行してホーム画面に戻るアニメーションではなく、クラッシュしたようにユーザーに表示されます。また、exitを呼び出す
-applicationWillTerminate:
と同様のUIApplicationDelegate
メソッドが呼び出されないため、データが保存されない場合があります。開発またはテスト中にアプリケーションを終了する必要がある場合は、
abort
関数またはassert
マクロが推奨されます
これは実際にはプログラムを終了する方法ではなく、人々に強制的に終了させる方法です。
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];
info.plistに移動し、「アプリケーションがバックグラウンドで実行されない」というキーを確認します。今回は、ユーザーがホームボタンをクリックすると、アプリケーションが完全に終了します。
追加UIApplicationExitsOnSuspend
のプロパティをapplication-info.plist
しますtrue
。
いくつかのテストの後、私は次のように言うことができます:
[UIApplication sharedApplication]
すると、アプリがクラッシュしたように見えますが、クラッシュする- (void)applicationWillTerminate:(UIApplication *)application
前に呼び出されます。exit(0);
もアプリケーションを終了しますが、「通常」のように見えます(スプリングボードのアイコンは期待どおりに表示され、ズームアウト効果があります)。ただし、- (void)applicationWillTerminate:(UIApplication *)application
デリゲートメソッドは呼び出されません。私のアドバイス:
- (void)applicationWillTerminate:(UIApplication *)application
デリゲートのを手動で呼び出します。exit(0);
ます。ApplicationDelegateは、ユーザーによる意図的な終了の通知を受け取ります。
- (void)applicationWillResignActive:(UIApplication *)application {
この通知を受け取ったら、電話します
exit(0);
これはすべての作業を行います。そして最高のことは、それはユーザーが終了することを意図していることです。そのため、ここでそれを呼び出すことは問題になりません。
私のオーディオアプリでは、音楽の再生中に他のユーザーがデバイスを同期した後にアプリを終了する必要がありました。同期が完了するとすぐに通知が届きます。しかし、その直後にアプリを終了すると、実際にはクラッシュのように見えます。
したがって、代わりに次のバックグラウンドアクションでアプリを本当に終了するようにフラグを設定します。同期後にアプリを更新しても問題ありません。
私のアプリは最近拒否されましたbc私は文書化されていない方法を使用しました。文字通り:
「残念ながら、プライベートAPIを使用しているため、App Storeに追加できません。iPhone開発者プログラムライセンス契約のセクション3.3.1で概説されている非パブリックAPIの使用は禁止されています。
「3.3.1アプリケーションはAppleが規定する方法でのみ文書化されたAPIを使用でき、プライベートAPIを使用または呼び出してはなりません。」
アプリケーションに含まれている非公開APIはterminateWithSuccessです
アップルは言う:
「警告:exit関数を呼び出さないでください。exitを呼び出すアプリケーションは、正常な終了を実行してホーム画面に戻るアニメーションではなく、クラッシュしたようにユーザーに表示されます。」
これは悪い仮定だと思います。ユーザーが終了ボタンをタップすると、「アプリケーションを終了します。」などのメッセージが表示されても、クラッシュしたようには見えません。Appleは、アプリケーションを終了する有効な方法を提供する必要があります(exit(0)ではありません)。
これは良い答えを得ましたが、少し拡大することにしました:
AppleのiOSヒューマンインターフェイスガイドラインを十分に読まないと、アプリケーションをAppStoreに受け入れられません。(彼らはあなたに対して彼らに対して何かをすることを拒否する権利を保持します)「プログラムで終了しないでください」セクションhttp://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices。 html は、この場合の扱い方に関する正確なガイドラインです。
Appleプラットフォームで問題が発生した場合、簡単に解決策を見つけることができません。HIGにご相談ください。Appleがあなたにそれを望まないだけの可能性もあり、彼らは通常(私はAppleではないので常に保証することはできません)彼らのドキュメントでそう述べています。
アプリケーションがインターネット接続を必要とする場合、アプリケーションを終了する必要があるかもしれません。アラートを表示してから、次のようにすることができます。
if ([[UIApplication sharedApplication] respondsToSelector:@selector(terminate)]) {
[[UIApplication sharedApplication] performSelector:@selector(terminate)];
} else {
kill(getpid(), SIGINT);
}
exit(0)
、abort()
関数を使用してアプリを終了することはできません。Appleはこれらの関数の使用を強く推奨していません。ただし、この関数は開発やテストの目的で使用できます。
開発またはテスト中にアプリケーションを終了する必要がある場合は、アボート機能またはアサートマクロが推奨されます
詳細については、このApple Q&Aスレッドを見つけてください。
この機能を使用すると、アプリケーションがクラッシュするような印象を与えます。そのため、特定の機能が利用できないため、アプリを閉じることをユーザーに知らせる終了メッセージ付きのアラートを表示できるというような提案を受けました。
ただし、アプリの起動と停止に関するiOSヒューマンインターフェイスガイドラインでは、「終了」または「閉じる」ボタンを使用してアプリケーションを終了しないことを推奨しています。むしろ、彼らは状況を説明するために適切なメッセージを表示することを提案しているということです。
iOSアプリは、閉じるまたは終了オプションを表示しません。ユーザーは、別のアプリに切り替えたり、ホーム画面に戻ったり、デバイスをスリープモードにしたりすると、アプリの使用を停止します。
プログラムでiOSアプリを終了しないでください。人々はこれをクラッシュと解釈する傾向があります。何かが原因でアプリが意図したとおりに機能しなくなった場合は、ユーザーに状況を伝え、ユーザーが何ができるかを説明する必要があります。
上記に加えて、私が追加したかっただけの良い、答え、あなたの記憶をきれいにすることを考えてください。
アプリケーションが終了すると、iPhone OSは残されたアプリケーションを自動的にクリーンアップするため、すべてのメモリを手動で解放しても、アプリケーションが終了するまでの時間が長くなるだけです。
- (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);
}
}
上記の[[NSMutableArray new] addObject:nil]アプローチを使用して、tell-tale exit(0)関数を呼び出さずにアプリを強制終了(クラッシュ)しました。
どうして?私のアプリはすべてのネットワークAPI呼び出しで証明書のピン留めを使用して、中間者攻撃を防止しているためです。これには、金融アプリが起動時に行う初期化呼び出しが含まれます。
証明書の認証に失敗すると、すべての初期化呼び出しでエラーが発生し、アプリが不確定な状態のままになります。ユーザーが家に帰ってからアプリに戻ることはできません。アプリがOSによって削除されない限り、まだ初期化されておらず、信頼できないためです。
したがって、この1つのケースでは、アプリが安全でない環境で動作していることをユーザーに通知するアラートを表示し、ユーザーが「閉じる」をクリックしたときに、前述の方法を使用してアプリを強制終了することをお勧めします。
[[UIApplication sharedApplication] terminateWithSuccess];
それはうまくいき、自動的に電話をかけました
- (void)applicationWillTerminateUIApplication *)application delegate.
コンパイル時の警告を削除するには、このコードを追加します
@interface UIApplication(MyExtras)
- (void)terminateWithSuccess;
@end
関数exit(0)
を直接呼び出さないでください。関数をすぐに終了し、アプリがクラッシュしたように見えます。したがって、ユーザーに確認アラートを表示して、ユーザーが自分でこれを実行できるようにする方が良いでしょう。
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()
}
}
iPadOS 13では、次のようにすべてのシーンセッションを閉じることができます。
for session in UIApplication.shared.openSessions {
UIApplication.shared.requestSceneSessionDestruction(session, options: nil, errorHandler: nil)
}
これapplicationWillTerminate(_ application: UIApplication)
により、アプリデリゲートが呼び出され、最終的にアプリが終了します。
ただし、次の2つのことに注意してください。
これは、すべてのシーンを閉じるために使用することを意図したものではありません。(https://developer.apple.com/design/human-interface-guidelines/ios/system-capabilities/multiple-windows/を参照)
iPhoneのiOS 13でコンパイルして正常に動作しますが、何もしないようです。
iOS / iPadOS 13のシーンに関する詳細:https ://developer.apple.com/documentation/uikit/app_and_environment/scenes
位置情報の更新を取得する(そのために位置情報の更新のバックグラウンド機能を使用するなど)ために、バックグラウンドで実行される長命のアプリである場合は、アプリを終了することが適切な場合があります。
たとえば、ユーザーが位置情報ベースのアプリからログアウトし、ホームボタンを使用してアプリをバックグラウンドにプッシュするとします。この場合、アプリは引き続き実行される可能性がありますが、完全に終了することは理にかなっています。これはユーザーにとっては適切であり(使用する必要のないメモリやその他のリソースを解放する)、アプリの安定性にとっては有効です(つまり、可能な場合は定期的にアプリを定期的に再起動することで、メモリリークやその他のメモリ不足に対するセーフティネットを確保できます。問題)。
これは(おそらくすべきではありませんが、以下を参照してください:-)次のようなもので実現できます。
- (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.htmlexit(0)
を参照する他の回答のように、フォアグラウンドで実行される平均的な本番アプリには使用することは決して適切ではありません。