Ich programmiere eine iPhone-App und muss sie aufgrund bestimmter Benutzeraktionen zum Beenden zwingen. Welche Methode kann nach dem Bereinigen des von der App zugewiesenen Speichers aufgerufen werden, um die Anwendung zu beenden?
Ich programmiere eine iPhone-App und muss sie aufgrund bestimmter Benutzeraktionen zum Beenden zwingen. Welche Methode kann nach dem Bereinigen des von der App zugewiesenen Speichers aufgerufen werden, um die Anwendung zu beenden?
Antworten:
Hast du es versucht exit(0)
?
Alternativ, [[NSThread mainThread] exit]
obwohl ich nicht versucht habe, dass es die geeignetere Lösung zu sein scheint.
Auf dem iPhone gibt es kein Konzept zum Beenden einer App. Die einzige Aktion, die dazu führen sollte, dass eine App beendet wird, ist das Berühren der Home-Taste auf dem Telefon. Darauf haben Entwickler keinen Zugriff.
Laut Apple sollte Ihre App nicht von alleine beendet werden. Da der Benutzer die Home-Taste nicht gedrückt hat, vermittelt jede Rückkehr zum Startbildschirm den Eindruck, dass Ihre App abgestürzt ist. Dies ist verwirrendes, nicht standardmäßiges Verhalten und sollte vermieden werden.
exit (0) wird einem Benutzer als Absturz angezeigt. Zeigen Sie dem Benutzer daher eine Bestätigungsmeldung an. Nach der Bestätigung aussetzen (Home-Taste programmgesteuert drücken) und 2 Sekunden warten, während die App mit Animation im Hintergrund angezeigt wird, dann hinter der Ansicht des Benutzers beenden
-(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)
spielt keine Rolle. Punkt ist, dass Ihre App "Beendigungsverhalten" hat. Das Beenden des Verhaltens selbst ist im AppStore verboten, mit Ausnahme einiger Apps, die von sehr wichtigen Drittanbietern erstellt wurden. Die Nachahmung des Verhaltens der Home-Taste kann ebenfalls abgelehnt werden.
Überprüfen Sie die Fragen und Antworten hier: https://developer.apple.com/library/content/qa/qa1561/_index.html
F: Wie beende ich meine iOS-Anwendung programmgesteuert?
Es ist keine API zum ordnungsgemäßen Beenden einer iOS-Anwendung verfügbar.
Unter iOS drückt der Benutzer die Home-Taste, um Anwendungen zu schließen. Sollte Ihre Anwendung Bedingungen haben, unter denen sie ihre beabsichtigte Funktion nicht bereitstellen kann, wird empfohlen, dem Benutzer eine Warnung anzuzeigen, die die Art des Problems und mögliche Maßnahmen angibt, die der Benutzer ergreifen könnte - Einschalten von WLAN, Aktivieren von Ortungsdiensten usw. Ermöglichen Sie dem Benutzer, die Anwendung nach eigenem Ermessen zu beenden.
WARNUNG: Rufen Sie die
exit
Funktion nicht auf. Anwendungen, die aufrufenexit
, scheinen dem Benutzer abgestürzt zu sein, anstatt eine ordnungsgemäße Beendigung durchzuführen und zum Startbildschirm zurückzukehren.Darüber hinaus werden Daten möglicherweise nicht gespeichert, da
-applicationWillTerminate:
ähnlicheUIApplicationDelegate
Methoden nicht aufgerufen werden, wenn Sie exit aufrufen.Wenn es während der Entwicklung oder des Testens erforderlich ist, Ihre Anwendung zu beenden, wird die
abort
Funktion oder dasassert
Makro empfohlen
Es ist nicht wirklich eine Möglichkeit, das Programm zu beenden, sondern eine Möglichkeit, die Leute zum Beenden zu zwingen.
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];
Gehen Sie zu Ihrer info.plist und aktivieren Sie den Schlüssel "Anwendung läuft nicht im Hintergrund". Dieses Mal, wenn der Benutzer auf die Home-Schaltfläche klickt, wird die Anwendung vollständig beendet.
UIApplicationExitsOnSuspend
Eigenschaft hinzufügen application-info.plist
zu true
.
Nach einigen Tests kann ich Folgendes sagen:
[UIApplication sharedApplication]
Die App sieht aus, als wäre sie abgestürzt, ABER sie wird - (void)applicationWillTerminate:(UIApplication *)application
vorher aufgerufen .exit(0);
wird auch die Anwendung beendet, sie sieht jedoch "normal" aus (die Symbole des Sprungbretts werden wie erwartet mit dem Verkleinerungseffekt angezeigt), ABER die - (void)applicationWillTerminate:(UIApplication *)application
Delegate-Methode wird nicht aufgerufen .Mein Rat:
- (void)applicationWillTerminate:(UIApplication *)application
den Delegierten manuell an.exit(0);
.Ihr ApplicationDelegate wird vom Benutzer über das absichtliche Beenden informiert:
- (void)applicationWillResignActive:(UIApplication *)application {
Wenn ich diese Benachrichtigung erhalte, rufe ich einfach an
exit(0);
Welches macht die ganze Arbeit. Und das Beste ist, es ist die Absicht des Benutzers, das Programm zu beenden, weshalb dies kein Problem sein sollte, es dort aufzurufen.
In meiner Audio-App musste die App beendet werden, nachdem Benutzer ihr Gerät synchronisiert hatten, während die Musik noch abgespielt wurde. Sobald die Synchronisierung abgeschlossen ist, erhalte ich eine Benachrichtigung. Aber das Beenden der App gleich danach würde tatsächlich wie ein Absturz aussehen.
Also habe ich stattdessen ein Flag gesetzt, um die App bei der nächsten Hintergrundaktion WIRKLICH zu beenden. Welches ist in Ordnung, um die App nach einer Synchronisierung zu aktualisieren.
Meine App wurde kürzlich abgelehnt, da ich eine undokumentierte Methode verwendet habe. Buchstäblich:
"Leider kann es nicht zum App Store hinzugefügt werden, da eine private API verwendet wird. Die Verwendung nicht öffentlicher APIs ist gemäß Abschnitt 3.3.1 der Lizenzvereinbarung für das iPhone Developer Program verboten:
"3.3.1 Anwendungen dürfen dokumentierte APIs nur in der von Apple vorgeschriebenen Weise verwenden und dürfen keine privaten APIs verwenden oder aufrufen."
Die nicht öffentliche API, die in Ihrer Anwendung enthalten ist, lautet terminateWithSuccess. "
Apple sagt:
"Warnung: Rufen Sie die Exit-Funktion nicht auf. Anwendungen, die exit aufrufen, scheinen dem Benutzer abgestürzt zu sein, anstatt eine ordnungsgemäße Beendigung durchzuführen und zum Startbildschirm zurückzukehren."
Ich denke, dass dies eine schlechte Annahme ist. Wenn der Benutzer auf eine Schaltfläche zum Beenden tippt und eine Meldung mit dem Titel "Die Anwendung wird jetzt beendet." Angezeigt wird, scheint sie nicht abgestürzt zu sein. Apple sollte eine gültige Möglichkeit zum Beenden einer Anwendung bereitstellen (nicht beenden (0)).
Dies hat eine gute Antwort bekommen, aber beschlossen, ein wenig zu erweitern:
Sie können Ihre Bewerbung nicht in den AppStore aufnehmen, ohne die Richtlinien für die iOS-Benutzeroberfläche von Apple gut gelesen zu haben. (Sie behalten sich das Recht vor, Sie abzulehnen, wenn Sie etwas gegen sie unternehmen. ) Der Abschnitt "Nicht programmgesteuert beenden" http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices. html ist eine genaue Richtlinie, wie Sie in diesem Fall behandeln sollten.
Wenn Sie jemals ein Problem mit der Apple-Plattform haben, für das Sie keine einfache Lösung finden können, wenden Sie sich an HIG. Es ist möglich, dass Apple einfach nicht möchte, dass Sie es tun, und sie sagen dies normalerweise (ich bin nicht Apple, daher kann ich nicht immer garantieren) in ihrer Dokumentation.
Hm, möglicherweise müssen Sie die Anwendung beenden, wenn Ihre Anwendung beispielsweise eine Internetverbindung erfordert. Sie könnten eine Warnung anzeigen und dann Folgendes tun:
if ([[UIApplication sharedApplication] respondsToSelector:@selector(terminate)]) {
[[UIApplication sharedApplication] performSelector:@selector(terminate)];
} else {
kill(getpid(), SIGINT);
}
Wir können nicht aufhören App exit(0)
, abort()
Funktionen, wie die von Apple dringend die Verwendung dieser Funktionen entmutigen. Sie können diese Funktionen jedoch zu Entwicklungs- oder Testzwecken verwenden.
Wenn es während der Entwicklung oder des Testens erforderlich ist, Ihre Anwendung zu beenden, wird die Abbruchfunktion oder das Assert-Makro empfohlen
Weitere Informationen finden Sie in diesem Apple Q & A- Thread.
Wenn Sie diese Funktion verwenden, entsteht der Eindruck, als würde die Anwendung abstürzen. Daher habe ich einen Vorschlag erhalten, wie wir dem aufmerksamen Benutzer eine Benachrichtigung über die Beendigung der App anzeigen können, da bestimmte Funktionen nicht verfügbar sind.
Die iOS-Benutzeroberfläche für das Starten und Stoppen der App empfiehlt jedoch, niemals die Schaltfläche Beenden oder Schließen zu verwenden, um die Anwendung zu beenden. Eher als dass sie vorschlagen, die richtige Nachricht anzuzeigen, um die Situation zu erklären.
Eine iOS-App zeigt niemals die Option Schließen oder Beenden an. Benutzer verwenden eine App nicht mehr, wenn sie zu einer anderen App wechseln, zum Startbildschirm zurückkehren oder ihre Geräte in den Ruhemodus versetzen.
Beenden Sie eine iOS-App niemals programmgesteuert. Die Leute neigen dazu, dies als Absturz zu interpretieren. Wenn etwas Ihre App daran hindert, wie beabsichtigt zu funktionieren, müssen Sie den Benutzern die Situation mitteilen und erklären, was sie dagegen tun können.
Zusätzlich zu der obigen, guten Antwort, die ich nur hinzufügen wollte, denken Sie darüber nach, Ihr Gedächtnis aufzuräumen.
Nach dem Beenden Ihrer Anwendung bereinigt das iPhone-Betriebssystem automatisch alles, was Ihre Anwendung zurückgelassen hat. Wenn Sie also den gesamten Speicher manuell freigeben, kann sich die Zeit, die Ihre Anwendung zum Beenden benötigt, nur verlängern.
- (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);
}
}
Ich habe den oben erwähnten Ansatz [[NSMutableArray new] addObject: nil] verwendet, um die App zu beenden (abzustürzen), ohne einen verräterischen Funktionsaufruf zum Beenden (0) auszuführen.
Warum? Weil meine App bei allen Netzwerk-API-Aufrufen das Anheften von Zertifikaten verwendet, um Man-in-the-Middle-Angriffe zu verhindern. Dazu gehören die Initialisierungsaufrufe, die meine Finanz-App beim Start ausführt.
Wenn die Zertifikatauthentifizierung fehlschlägt, rufen alle meine Initialisierungsfehler auf und lassen meine App in einem unbestimmten Zustand. Es hilft nicht, den Benutzer nach Hause und dann zurück in die App zu lassen, da die App, sofern sie nicht vom Betriebssystem gelöscht wurde, immer noch nicht initialisiert und nicht vertrauenswürdig ist.
In diesem Fall halten wir es für am besten, eine Warnung auszulösen, die den Benutzer darüber informiert, dass die App in einer unsicheren Umgebung ausgeführt wird, und dann, wenn er auf "Schließen" klickt, das Beenden der App mit der oben genannten Methode zu erzwingen.
[[UIApplication sharedApplication] terminateWithSuccess];
Es hat gut funktioniert und ruft automatisch an
- (void)applicationWillTerminateUIApplication *)application delegate.
Fügen Sie diesen Code hinzu, um die Warnung zur Kompilierungszeit zu entfernen
@interface UIApplication(MyExtras)
- (void)terminateWithSuccess;
@end
Sie sollten die Funktion nicht direkt aufrufen exit(0)
da sie die Anwendung sofort beendet und so aussieht, als wäre Ihre App abgestürzt. Zeigen Sie den Benutzern daher besser eine Bestätigungsbenachrichtigung und lassen Sie sie dies selbst tun.
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()
}
}
Der Benutzer sollte entscheiden, wann eine App beendet wird. Ich denke nicht, dass es eine gute Benutzerinteraktion ist, wenn eine App beendet wird. Daher gibt es keine nette API dafür, nur die Home-Schaltfläche hat eine.
Wenn ein Fehler auftritt: Implementieren Sie ihn besser oder benachrichtigen Sie den Benutzer. Wenn ein Neustart erforderlich ist: Implementieren Sie ihn besser, indem Sie den Benutzer benachrichtigen.
Es klingt dumm, aber es ist eine schlechte Praxis, die App zu beenden, ohne den Benutzer entscheiden zu lassen und ihn nicht zu benachrichtigen. Und da es laut Apple eine Home-Taste für die Benutzerinteraktion gibt, sollte es nicht zwei Dinge für dieselbe Funktion geben (Beenden einer App).
Das Beenden einer App auf eine andere Weise als die Home-Schaltfläche ist ein nicht iOS-ähnlicher Ansatz.
Ich habe diesen Helfer gemacht, der keine privaten Sachen benutzt:
void crash()
{ [[NSMutableArray new] addObject:NSStringFromClass(nil)]; }
Aber in meinem Fall immer noch nicht für die Produktion gedacht. Es dient zum Testen von Absturzberichten oder zum schnellen Neustart nach einem Zurücksetzen der Kerndaten. Ich habe es nur sicher gemacht, nicht abgelehnt zu werden, wenn die Funktion im Produktionscode verbleibt.
In iPadOS 13 können Sie jetzt alle Szenensitzungen wie folgt schließen:
for session in UIApplication.shared.openSessions {
UIApplication.shared.requestSceneSessionDestruction(session, options: nil, errorHandler: nil)
}
Dadurch wird applicationWillTerminate(_ application: UIApplication)
Ihr App-Delegierter aufgerufen und die App am Ende beendet.
Aber Vorsicht vor zwei Dingen:
Dies ist sicherlich nicht zum Schließen aller Szenen gedacht . (Siehe https://developer.apple.com/design/human-interface-guidelines/ios/system-capabilities/multiple-windows/. )
Es kompiliert und läuft gut unter iOS 13 auf einem iPhone, scheint aber nichts zu tun.
Weitere Informationen zu Szenen in iOS / iPadOS 13: https://developer.apple.com/documentation/uikit/app_and_environment/scenes
Es kann angebracht sein, eine App zu beenden, wenn es sich um eine langlebige App handelt, die auch im Hintergrund ausgeführt wird, z. B. um Standortaktualisierungen abzurufen (mithilfe der Standortaktualisierungen) Hintergrundfunktion für ).
Angenommen, der Benutzer meldet sich von Ihrer standortbasierten App ab und schiebt die App mithilfe der Home-Schaltfläche in den Hintergrund. In diesem Fall läuft Ihre App möglicherweise weiter, es kann jedoch sinnvoll sein, sie vollständig zu beenden. Dies ist gut für den Benutzer (gibt Speicher und andere Ressourcen frei, die nicht verwendet werden müssen) und ist gut für die Stabilität der App (dh es muss sichergestellt werden, dass die App regelmäßig neu gestartet wird, wenn dies möglich ist. Dies ist ein Sicherheitsnetz gegen Speicherlecks und anderen geringen Speicher Probleme).
Dies könnte (sollte aber wahrscheinlich nicht, siehe unten :-) mit etwas erreicht werden wie:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if (/* logged out */) {
exit(0);
} else {
// normal handling.
}
}
Da die App dann aus dem Hintergrund beendet wird, sieht sie für den Benutzer nicht falsch aus und ähnelt keinem Absturz, vorausgesetzt, die Benutzeroberfläche wird beim nächsten Ausführen der App wiederhergestellt. Mit anderen Worten, für den Benutzer würde es nicht anders aussehen als eine vom System initiierte Beendigung der App, wenn sich die App im Hintergrund befindet.
Es wäre jedoch vorzuziehen, einen Standardansatz zu verwenden, um das System darüber zu informieren, dass die App beendet werden kann. In diesem Fall können Sie beispielsweise sicherstellen, dass das GPS nicht verwendet wird, indem Sie die Anforderung von Standortaktualisierungen beenden, einschließlich des Deaktivierens der Anzeige des aktuellen Standorts in einer Kartenansicht, falls vorhanden. Auf diese Weise sorgt das System dafür, dass die App einige Minuten (dh [[UIApplication sharedApplication] backgroundTimeRemaining]
) nach dem Eintritt der App in den Hintergrund beendet wird. Dies würde dieselben Vorteile bringen, ohne dass Code zum Beenden der App verwendet werden müsste.
- (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.
}
}
Und natürlich exit(0)
wäre die Verwendung niemals für die durchschnittliche Produktions-App geeignet, die im Vordergrund ausgeführt wird, wie aus anderen Antworten hervorgeht, die auf http://developer.apple.com/iphone/library/qa/qa2008/qa1561.html verweisen