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 de l'application allouée, quelle est la méthode appropriée à appeler pour mettre fin à l'application?
Avez-vous essayé exit(0)
?
Alternativement, [[NSThread mainThread] exit]
, bien que je n’aie pas essayé, cela semble être la solution la plus appropriée.
Sur l'iPhone, il n'y a pas de concept pour quitter une application. La seule action à l'origine de la fermeture d'une application consiste à appuyer sur le bouton Accueil du téléphone. Les développeurs n'y ont pas accès.
Selon Apple, votre application ne doit pas se terminer seule. Comme 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 déroutant, comportement non standard et devrait être évité.
exit (0) apparaît pour un utilisateur en tant que plantage, montrez-lui un message de confirmation. Après confirmation, suspendre (appuyer sur le bouton d'accueil par programmation) et attendre 2 secondes pendant que l'application passe en arrière-plan avec animation puis quitter derrière 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);
}
}
Ce n'est pas vraiment un moyen de quitter le programme, mais un moyen de forcer les gens à quitter.
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];
Consultez le Q & A ici: https://developer.Apple.com/library/content/qa/qa1561/_index.html
Q: Comment puis-je quitter mon application iOS par programme?
Aucune API n'est fournie pour mettre fin gracieusement à une application iOS.
Dans iOS, l'utilisateur appuie sur le bouton Accueil pour fermer les applications. Si votre application rencontre des conditions dans lesquelles elle ne peut pas fournir la fonction voulue, il est recommandé d'afficher une alerte pour l'utilisateur indiquant la nature du problème et les actions possibles que l'utilisateur pourrait entreprendre: activer le WiFi, activer les services de localisation, etc. Permettre à l'utilisateur de mettre fin à l'application à sa propre discrétion.
AVERTISSEMENT: N'appelez pas la fonction
exit
. Les applications qui appellentexit
auront l’impression que l’utilisateur est tombé en panne, plutôt que de procéder à une fermeture harmonieuse et de revenir à l’écran d’accueil.De plus, les données peuvent ne pas être sauvegardées, car les méthodes
-applicationWillTerminate:
etUIApplicationDelegate
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, il est recommandé d'utiliser la fonction
abort
ouassert
.
Accédez à votre info.plist et cochez la case "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 la propriété UIApplicationExitsOnSuspend
sur application-info.plist
à true
.
Après quelques tests, je peux dire ce qui suit:
[UIApplication sharedApplication]
donnera à l'application une apparence de plantage, MAIS elle appellera - (void)applicationWillTerminate:(UIApplication *)application
avant de le faire;exit(0);
mettra également fin à l'application, mais elle aura l'air "normale" (les icônes du springboard apparaîtront comme prévu avec l'effet de zoom arrière), MAIS elle n'appellera pas la méthode déléguée - (void)applicationWillTerminate:(UIApplication *)application
.Mon conseil:
- (void)applicationWillTerminate:(UIApplication *)application
sur le délégué.exit(0);
.Votre ApplicationDelegate est averti de la fermeture intentionnelle de l'utilisateur:
- (void)applicationWillResignActive:(UIApplication *)application {
Lorsque je reçois cette notification, j'appelle
exit(0);
Qui fait tout le travail. Et le mieux, c’est l’intention de l’utilisateur de quitter, c’est pourquoi il ne devrait pas y avoir de problème à l’appeler là-bas.
Sur mon application audio, il était nécessaire de quitter l'application une fois que les personnes synchronisaient leur appareil alors que la musique était encore 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 réalité à un crash.
Donc, au lieu de cela, j'ai défini un drapeau pour quitter VRAIMENT l'application lors de la prochaine action d'arrière-plan. Ce qui est correct pour actualiser l'application après une synchronisation.
Mon application a été rejetée récemment parce que j'ai utilisé une méthode non documentée. Littéralement:
"Malheureusement, il ne peut pas être ajouté à l'App Store, car il utilise une API privée. Utilisation d'API non publiques, qui, comme indiqué dans le Contrat de licence du programme pour développeur iPhone, est interdit:
"3.3.1 Les applications ne peuvent utiliser les API documentées que de la manière prescrite par Apple et ne doivent ni utiliser ni 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 qui appellent l'exit apparaîtront comme plâtrées à l'utilisateur, plutôt que d'exécuter une résiliation en douceur et de revenir à l'écran d'accueil."
Je pense que c'est une mauvaise hypothèse. Si l'utilisateur appuie sur un bouton de fermeture et qu'un message apparaît, par exemple: "L'application va maintenant quitter", il ne semble pas avoir été bloqué. Apple devrait fournir un moyen valide de quitter une application (pas de quitter (0)).
Cela a eu une bonne réponse mais a décidé de développer un peu:
Vous ne pouvez pas accepter votre application sur AppStore sans avoir lu attentivement les consignes relatives à l'interface utilisateur iOS d'Apple. (Ils conservent le droit de vous refuser pour faire quoi que ce soit contre eux) La section "Ne pas quitter par programme" http: // développeur .Apple.com/library/ios/# DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices.html indique exactement comment vous devez traiter dans ce cas.
Si vous rencontrez un problème avec la plate-forme Apple pour laquelle vous ne pouvez pas trouver facilement une solution, consultez HIG. Il est possible que 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) le disent dans leur documentation.
Nous ne pouvons pas quitter l'application avec les fonctions exit(0)
, abort()
, car Apple décourage fortement l'utilisation 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 assert est recommandée.
Trouvez ce fil Apple Q & A pour obtenir plus d'informations.
Comme l'utilisation de cette fonction crée l'impression que l'application se bloque. J'ai donc quelques suggestions, comme nous pouvons afficher un message d'alerte avec résiliation à l'utilisateur averti de la fermeture de l'application, en raison de l'indisponibilité de certaines fonctionnalités.
Mais la directive d'interface humaine iOS pour démarrage et arrêt de l'application , suggérant que ne jamais utiliser le bouton Quitter ou Fermer pour terminer l'application. Plutôt que de suggérer d’afficher un message approprié pour expliquer la situation.
Une application iOS n'affiche jamais une option Fermer ou Quitter. Les utilisateurs arrêtent d'utiliser une application lorsqu'ils basculent vers 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 accident. 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 faire à ce sujet.
En plus de ce qui précède, bon, je voulais juste ajouter une réponse, pensez à nettoyer votre mémoire.
Une fois votre application fermée, le système d'exploitation de l'iPhone nettoie automatiquement tout ce que votre application a laissé. Par conséquent, la libération manuelle de la mémoire ne peut que rallonger le temps nécessaire à la fermeture de votre application.
Hm, vous devrez peut-être quitter l'application si, par exemple, votre application nécessite une connexion Internet. Vous pouvez afficher une alerte et faire quelque chose comme ceci:
if ([[UIApplication sharedApplication] respondsToSelector:@selector(terminate)]) {
[[UIApplication sharedApplication] performSelector:@selector(terminate)];
} else {
kill(getpid(), SIGINT);
}
- (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 de l'application sans effectuer d'appel de fonction exit (0).
Pourquoi? Parce que mon application utilise l'épinglage de certificat sur tous les appels d'API réseau pour empêcher les attaques de type "man-in-the-middle". Ceux-ci incluent les appels d'initialisation que mon application financière effectue au démarrage.
Si l'authentification par certificat échoue, tous mes appels d'initialisation génèrent une erreur et laissent mon application dans un état indéterminé. Laisser l'utilisateur rentrer chez lui puis de nouveau dans l'application n'aide pas, car à moins que l'application ait été purgée par le système d'exploitation, elle n'est toujours pas initialisée et n'est pas digne de confiance.
Donc, dans ce cas, nous avons jugé préférable de déclencher une alerte pour informer l'utilisateur que l'application fonctionne dans un environnement non sécurisé, puis, lorsqu'ils cliquent sur "Fermer", forcer la fermeture de l'application à l'aide de 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 à un crash de votre application. 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 utilisateur lorsqu'une application se ferme. Par conséquent, il n'y a pas d'API Nice pour cela, seul le bouton d'accueil en a une.
En cas d'erreur: implémentez-le mieux ou notifiez l'utilisateur. S'il doit y avoir un redémarrage: implémentez-le mieux Avisez l'utilisateur.
Cela semble stupide, mais c'est une mauvaise pratique de quitter l'application sans laisser l'utilisateur décider et de ne pas le prévenir. Et comme il existe un bouton d'accueil pour l'interaction utilisateur, Apple, il ne devrait pas y avoir deux choses pour la même fonction (quitter une application).
Quitter une application autrement que par le bouton principal est = vraiment non-iOS-esque.
J'ai fait cette aide, cependant, qui n'utilise aucune substance privée:
void crash()
{ [[NSMutableArray new] addObject:NSStringFromClass(nil)]; }
Mais toujours pas destiné à la production dans mon cas. Il sert à tester les rapports d'incident ou à redémarrer rapidement après une réinitialisation des données de base. Juste fait en sécurité pour ne pas être rejeté si la fonction est laissée dans le code de production.
Il peut être approprié de quitter une application s'il s'agit d'une application longue durée qui s'exécute également en arrière-plan, par exemple pour obtenir des mises à jour d'emplacement (à l'aide du mises à jour d'emplacement capacité d'arrière-plan pour cela).
Par exemple, supposons que l'utilisateur se déconnecte de votre application basée sur la localisation et place 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 quitter complètement. Cela serait bon pour l'utilisateur (libère de la mémoire et d'autres ressources qu'il n'est pas nécessaire d'utiliser) et pour la stabilité de l'application (c'est-à-dire que le redémarrage périodique de l'application est un filet de sécurité contre les fuites de mémoire et les autres capacités de mémoire insuffisantes. 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.
}
}
Étant donné que l'application quitterait alors l'arrière-plan , l'utilisateur n'aurait pas l'air mal et ne ressemblerait pas à un blocage, à condition que l'interface utilisateur soit restaurée. la prochaine fois qu'ils exécutent l'application. En d'autres termes, pour l'utilisateur, cela ne ressemblerait en rien à une terminaison de l'application initié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 que le système sache que l'application peut être fermée. Par exemple, dans ce cas, assurez-vous que le GPS n'est pas utilisé en arrêtant de demander des mises à jour d'emplacement, notamment en désactivant l'affichage de l'emplacement actuel sur une vue cartographique, le cas échéant. De cette façon, le système se chargera de terminer l’application quelques minutes (par exemple [[UIApplication sharedApplication] backgroundTimeRemaining]
) après l’application de l’application en arrière-plan. Cela aurait tous 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, utiliser exit(0)
ne serait jamais approprié pour une application de production moyenne qui s'exécute au premier plan, comme indiqué dans les autres réponses qui font référence à http://developer.Apple.com/iphone/library/qa /qa2008/qa1561.html
Une bibliothèque appelée Darvin
peut être utilisée.
import Darwin
exit(0) // Here you go
NB: Ceci n'est pas recommandé dans les applications iOS.
Cela vous permettra d’obtenir un journal des collisions.