Je programme une application iPhone et je dois la forcer à quitter en raison de certaines actions de l'utilisateur. Après avoir nettoyé la mémoire allouée à l'application, quelle est la méthode appropriée pour appeler pour terminer l'application?
Je programme une application iPhone et je dois la forcer à quitter en raison de certaines actions de l'utilisateur. Après avoir nettoyé la mémoire allouée à l'application, quelle est la méthode appropriée pour appeler pour terminer l'application?
Réponses:
As-tu essayé exit(0)
?
Alternativement, [[NSThread mainThread] exit]
même si je n'ai pas essayé, cela semble être la solution la plus appropriée.
Sur l'iPhone, il n'est pas question de quitter une application. La seule action qui devrait provoquer la fermeture d'une application est de toucher le bouton Accueil du téléphone, et ce n'est pas quelque chose auquel les développeurs ont accès.
Selon Apple, votre application ne devrait pas s'arrêter d'elle-même. Étant donné que l'utilisateur n'a pas appuyé sur le bouton Accueil, tout retour à l'écran d'accueil donne à l'utilisateur l'impression que votre application s'est bloquée. Ceci est un comportement déroutant et non standard et doit être évité.
exit (0) apparaît à un utilisateur comme un plantage, affichez donc un message de confirmation à l'utilisateur. Après confirmation, suspendez (appuyez sur le bouton d'accueil par programme) et attendez 2 secondes pendant que l'application passe en arrière-plan avec l'animation, puis quittez la vue de l'utilisateur
-(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)
n'a pas d'importance. Le point est que votre application a un "comportement de fermeture". Quitter le comportement lui-même est interdit dans l'AppStore, à l'exception de quelques applications créées par des tiers très importants. De même, l'imitation du comportement du bouton d'accueil peut également être rejetée.
Consultez les questions et réponses ici: https://developer.apple.com/library/content/qa/qa1561/_index.html
Q: Comment quitter par programme mon application iOS?
Il n'y a pas d'API fournie pour terminer gracieusement une application iOS.
Sous iOS, l'utilisateur appuie sur le bouton Accueil pour fermer les applications. Si votre application présente des conditions dans lesquelles elle ne peut pas fournir la fonction prévue, l'approche recommandée consiste à afficher une alerte pour l'utilisateur qui indique la nature du problème et les actions possibles que l'utilisateur pourrait entreprendre - activer le WiFi, activer les services de localisation, etc. Autorisez l'utilisateur à résilier l'application à sa seule discrétion.
AVERTISSEMENT: n'appelez pas la
exit
fonction. Les applications appelantesexit
apparaîtront à l'utilisateur comme ayant planté, plutôt que d'effectuer une terminaison gracieuse et de revenir à l'écran d'accueil.En outre, les données peuvent ne pas être enregistrées, car
-applicationWillTerminate:
desUIApplicationDelegate
méthodes similaires ne seront pas appelées si vous appelez exit.Si, au cours du développement ou des tests, il est nécessaire de mettre fin à votre application, la
abort
fonction ou laassert
macro est recommandée
Ce n'est pas vraiment un moyen de quitter le programme, mais un moyen de forcer les gens à arrêter.
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];
Accédez à votre info.plist et vérifiez la clé "L'application ne s'exécute pas en arrière-plan". Cette fois, lorsque l'utilisateur clique sur le bouton d'accueil, l'application se ferme complètement.
Ajoutez une UIApplicationExitsOnSuspend
propriété application-info.plist
à true
.
Après quelques tests, je peux dire ce qui suit:
[UIApplication sharedApplication]
l'application semblera plantée, MAIS elle appellera - (void)applicationWillTerminate:(UIApplication *)application
avant de le faire;exit(0);
mettra également fin à l'application, mais elle semblera "normale" (les icônes du tremplin apparaissent comme prévu, avec l'effet de zoom arrière), MAIS elle n'appellera pas la - (void)applicationWillTerminate:(UIApplication *)application
méthode déléguée.Mon conseil:
- (void)applicationWillTerminate:(UIApplication *)application
sur le délégué.exit(0);
.Votre ApplicationDelegate est informé de la fermeture intentionnelle de l'utilisateur:
- (void)applicationWillResignActive:(UIApplication *)application {
Quand je reçois cette notification, j'appelle
exit(0);
Qui fait tout le travail. Et la meilleure chose est, c'est l'intention de l'utilisateur de quitter, c'est pourquoi cela ne devrait pas être un problème pour l'appeler là-bas.
Sur mon application audio, il était nécessaire de quitter l'application après que les gens synchronisaient leur appareil pendant que la musique était en cours de lecture. Dès que la synchronisation est terminée, je reçois une notification. Mais quitter l'application juste après cela ressemblerait en fait à un crash.
Au lieu de cela, j'ai défini un indicateur pour vraiment quitter l'application lors de la prochaine action de mise en arrière-plan. Ce qui est correct pour actualiser l'application après une synchronisation.
Mon application a été rejetée récemment car j'ai utilisé une méthode non documentée. Au sens propre:
"Malheureusement, il ne peut pas être ajouté à l'App Store car il utilise une API privée. L'utilisation d'API non publiques, comme indiqué dans la section 3.3.1 du contrat de licence du programme pour les développeurs iPhone, est interdite:
"3.3.1 Les applications ne peuvent utiliser les API documentées que de la manière prescrite par Apple et ne doivent pas utiliser ou appeler des API privées."
L'API non publique incluse dans votre application est terminateWithSuccess "
Apple dit:
"Avertissement: N'appelez pas la fonction de sortie. Les applications appelant exit apparaîtront à l'utilisateur comme ayant planté, plutôt que d'effectuer une terminaison gracieuse et de revenir à l'écran d'accueil."
Je pense que c'est une mauvaise hypothèse. Si l'utilisateur appuie sur un bouton Quitter et qu'un message s'affiche disant quelque chose comme: "L'application va maintenant se fermer.", Il ne semble pas être bloqué. Apple devrait fournir un moyen valide de quitter une application (pas de quitter (0)).
Cela a obtenu une bonne réponse mais a décidé de développer un peu:
Vous ne pouvez pas faire accepter votre application sur l'AppStore sans avoir bien lu les directives relatives à l'interface humaine iOS d'Apple. (ils se réservent le droit de vous rejeter pour quoi que ce soit contre eux) La section "Ne pas quitter par programme" http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices. html est une indication exacte de la façon dont vous devez traiter dans ce cas.
Si vous avez un problème avec la plate-forme Apple, vous ne pouvez pas facilement trouver de solution, consultez HIG. Il est possible qu'Apple ne veuille tout simplement pas que vous le fassiez et ils le font généralement (je ne suis pas Apple donc je ne peux pas toujours garantir) dans leur documentation.
Hm, vous devrez peut-être quitter l'application si, par exemple, votre application nécessite une connexion Internet. Vous pouvez afficher une alerte puis faire quelque chose comme ceci:
if ([[UIApplication sharedApplication] respondsToSelector:@selector(terminate)]) {
[[UIApplication sharedApplication] performSelector:@selector(terminate)];
} else {
kill(getpid(), SIGINT);
}
Nous ne pouvons pas quitter l' application à l' aide exit(0)
, les abort()
fonctions, comme Apple a fortement l'utilisation découragea de ces fonctions. Bien que vous puissiez utiliser ces fonctions à des fins de développement ou de test.
Si pendant le développement ou les tests, il est nécessaire de mettre fin à votre application, la fonction d'abandon ou la macro d'assertion est recommandée
Veuillez trouver ce fil Apple Q&A pour obtenir plus d'informations.
Lorsque vous utilisez cette fonction, créez une impression comme si l'application se bloquait. J'ai donc reçu une suggestion comme si nous pouvions afficher une alerte avec un message de résiliation pour informer l'utilisateur de la fermeture de l'application, en raison de l'indisponibilité de certaines fonctionnalités.
Mais la directive d'interface humaine iOS pour démarrer et arrêter l'application , suggérant que n'utilisez jamais le bouton Quitter ou Fermer pour terminer l'application. Ils suggèrent plutôt d'afficher un message approprié pour expliquer la situation.
Une application iOS n'affiche jamais une option Fermer ou Quitter. Les gens cessent d'utiliser une application lorsqu'ils passent à une autre application, reviennent à l'écran d'accueil ou mettent leurs appareils en mode veille.
Ne quittez jamais une application iOS par programme. Les gens ont tendance à interpréter cela comme un crash. Si quelque chose empêche votre application de fonctionner comme prévu, vous devez informer les utilisateurs de la situation et expliquer ce qu'ils peuvent y faire.
En plus de ce qui précède, bonne réponse que je voulais juste ajouter, pensez à nettoyer votre mémoire.
Après la fermeture de votre application, l'iPhone OS nettoie automatiquement tout ce que votre application a laissé derrière, de sorte que libérer toute la mémoire manuellement peut simplement augmenter la durée de fermeture de votre application.
- (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);
}
}
J'ai utilisé l'approche [[NSMutableArray new] addObject: nil] mentionnée ci-dessus pour forcer la fermeture (crash) de l'application sans effectuer d'appel de fonction d'exit (0) révélateur.
Pourquoi? Parce que mon application utilise l'épinglage de certificat sur tous les appels d'API réseau pour empêcher les attaques de l'homme du milieu. Il s'agit notamment des appels d'initialisation que mon application financière effectue au démarrage.
Si l'authentification par certificat échoue, toute mon initialisation appelle l'erreur et laisse mon application dans un état indéterminé. Laisser l'utilisateur rentrer chez lui, puis revenir dans l'application n'aide pas, car à moins que l'application n'ait été purgée par le système d'exploitation, elle n'est toujours pas initialisée et n'est pas fiable.
Donc, dans ce cas, nous avons jugé préférable de déclencher une alerte informant l'utilisateur que l'application fonctionne dans un environnement non sécurisé, puis, lorsqu'il clique sur "Fermer", forcer la fermeture de l'application en utilisant la méthode susmentionnée.
[[UIApplication sharedApplication] terminateWithSuccess];
Cela a bien fonctionné et appelle automatiquement
- (void)applicationWillTerminateUIApplication *)application delegate.
pour supprimer l'avertissement de compilation, ajoutez ce code
@interface UIApplication(MyExtras)
- (void)terminateWithSuccess;
@end
Vous ne devez pas appeler directement la fonction exit(0)
car elle quittera immédiatement l'application et ressemblera à votre application qui est en panne. Il vaut donc mieux montrer aux utilisateurs une alerte de confirmation et les laisser le faire eux-mêmes.
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()
}
}
L'utilisateur doit décider quand une application se ferme. Je ne pense pas que ce soit une bonne interaction avec l'utilisateur lorsqu'une application se ferme. Il n'y a donc pas de bonne API pour cela, seul le bouton d'accueil en a un.
S'il y a une erreur: mieux l'implémenter ou avertir l'utilisateur. S'il doit y avoir un redémarrage: implémentez-le mieux de notifiez l'utilisateur.
Cela semble stupide, mais c'est une mauvaise pratique de quitter l'application sans laisser l'utilisateur décider et sans l'avertir. Et comme il existe un bouton d'accueil pour l'interaction avec l'utilisateur, selon Apple, il ne devrait pas y avoir 2 choses pour la même fonction (quitter une application).
Quitter une application autrement que par le bouton d'accueil n'est vraiment pas iOS approche .
J'ai fait cet assistant, cependant, qui n'utilise aucun élément privé:
void crash()
{ [[NSMutableArray new] addObject:NSStringFromClass(nil)]; }
Mais toujours pas destiné à la production dans mon cas. C'est pour tester les rapports de plantage ou pour redémarrer rapidement après une réinitialisation des données de base. Juste fait en sorte de ne pas être rejeté si la fonction reste dans le code de production.
Dans iPadOS 13, vous pouvez maintenant fermer toutes les sessions de scène comme ceci:
for session in UIApplication.shared.openSessions {
UIApplication.shared.requestSceneSessionDestruction(session, options: nil, errorHandler: nil)
}
Cela fera appel applicationWillTerminate(_ application: UIApplication)
à votre délégué d'application et mettra fin à l'application à la fin.
Mais attention à deux choses:
Ce n'est certainement pas destiné à être utilisé pour fermer toutes les scènes. (voir https://developer.apple.com/design/human-interface-guidelines/ios/system-capabilities/multiple-windows/ )
Il se compile et fonctionne correctement sur iOS 13 sur un iPhone, mais semble ne rien faire.
Plus d'informations sur les scènes dans iOS / iPadOS 13: https://developer.apple.com/documentation/uikit/app_and_environment/scenes
Il peut être approprié de quitter une application s'il s'agit d'une application à longue durée de vie qui s'exécute également en arrière-plan, par exemple pour obtenir des mises à jour d'emplacement (à l'aide des mises à jour d'emplacement fonction d'arrière-plan des pour cela).
Par exemple, supposons que l'utilisateur se déconnecte de votre application basée sur la localisation et pousse l'application en arrière-plan à l'aide du bouton d'accueil. Dans ce cas, votre application peut continuer à fonctionner, mais il peut être judicieux de la fermer complètement. Ce serait bon pour l'utilisateur (libère de la mémoire et d'autres ressources qui n'ont pas besoin d'être utilisées), et bon pour la stabilité de l'application (c.-à-d. S'assurer que l'application est redémarrée périodiquement lorsque cela est possible est un filet de sécurité contre les fuites de mémoire et autres faibles mémoire) problèmes).
Cela pourrait (mais ne devrait probablement pas, voir ci-dessous :-) être réalisé avec quelque chose comme:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if (/* logged out */) {
exit(0);
} else {
// normal handling.
}
}
Puisque l'application sortirait alors de l'arrière-plan elle ne serait pas fausse pour l'utilisateur et ne ressemblerait pas à un plantage, à condition que l'interface utilisateur soit restaurée la prochaine fois qu'ils exécuteraient l'application. En d'autres termes, pour l'utilisateur, cela ne ressemblerait pas à une interruption de l'application déclenchée par le système lorsque l'application est en arrière-plan.
Néanmoins, il serait préférable d'utiliser une approche plus standard pour faire savoir au système que l'application peut être interrompue. Par exemple, dans ce cas, assurez-vous que le GPS n'est pas utilisé en arrêtant de demander des mises à jour de position, notamment en désactivant l'affichage de la position actuelle sur une vue de carte, le cas échéant. De cette façon, le système se chargera de mettre fin à l'application quelques minutes (c'est-à-dire [[UIApplication sharedApplication] backgroundTimeRemaining]
) après que l'application entre en arrière-plan. Cela aurait les mêmes avantages sans avoir à utiliser de code pour mettre fin à l'application.
- (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.
}
}
Et bien sûr, l'utilisation exit(0)
ne serait jamais appropriée pour l'application de production moyenne qui s'exécute au premier plan, selon d'autres réponses qui font référence à http://developer.apple.com/iphone/library/qa/qa2008/qa1561.html