2009-02-18 2 views
9

die folgende main() Methode betrachten, die Sie am meisten iPhone-Anwendungen finden würde:Warum hat die main() - Funktion einer iPhone-App nie eine Chance zum Beenden?

int main(int argc, char *argv[]) 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    int retVal = UIApplicationMain(argc, argv, nil, nil); 
    [pool release]; 
    return retVal; 
}

In jedem iPhone-App, die ich in Simulator habe laufen mit diesen (darunter mehrere Beispielprojekte von Apple), der Faden nie verlässt UIApplicationMain() und jeder verbleibende Code in main() wird nie ausgeführt. Ist das erwartetes Verhalten?

Ich habe überprüft, dass Anweisungen nach UIApplicationMain() nie ausgeführt werden, indem Sie den Code mit einem Debugger durchlaufen. Wenn der Benutzer eine Anwendung stoppt (z. B. durch Drücken der Schaltfläche "Home"), zeigt die resultierende Stapelüberwachung, dass [UIApplication _terminateWithStatus:] schließlich aufgerufen wird. Diese Funktion ruft die Methode applicationWillTerminate: Ihres Anwendungsdelegaten auf. Sobald dies beendet ist, scheint [UIApplication _terminateWithStatus:] den Thread zu beenden.

Kann jemand bestätigen, dass dies ist, wie main() funktionieren soll, oder zumindest das gleiche Verhalten auf ihrer Maschine bestätigen?

Antwort

19

Die ursprüngliche Frage war: „Warum nicht zu einem Haupt iPhone app() Funktion überhaupt eine Chance zu beenden?“

Kurze Antwort: Weil UIApplicationMain() codiert, so dass es nie zurückkehrt .

Nachdem ich mehrere Tests im Simulator und auf dem Gerät durchgeführt und einen anderen Entwickler gebeten habe, die gleichen Tests durchzuführen, habe ich bestätigt, dass UIApplicationMain nie zurückkehrt. Wenn der Benutzer eine Anwendung normal beendet, indem er die Home-Taste drückt, wird das Programm schließlich in einer nicht veröffentlichten UIApplication-Methode namens _terminateWithStatus beendet. Diese Methode ruft exit (0) auf.

Dieses Verhalten entspricht dem der NSApplicationMain-Funktion (die AppKit/Cocoa-Version der UIApplicationMain-Funktion ist). Die Dokumentation für NSApplicationMain() gibt eindeutig an, dass es nie zurückgeben wird.

Ich habe einen Fehler (6600198) an Apple eingereicht, der die offizielle Dokumentation (und die Xcode-Vorlage für main.m) anfordert, um zu bestätigen, dass UIApplicationMain() niemals zurückkehrt. Obwohl dies kein funktionelles Problem ist, sind die aktuelle Vorlage und die Dokumente irreführend.

Vielen Dank an alle für die Eingabe und Brainstorming!

+2

Update: Ich freue mich berichten zu können, dass Apple die offizielle Dokumentation für UIApplicationMain() geändert und meinen Fehler geschlossen hat. Die Dokumentation enthält jetzt Folgendes: Obwohl ein ganzzahliger Rückgabetyp angegeben ist, wird diese Funktion nie zurückgegeben. Wenn Benutzer eine iPhone-Anwendung durch Drücken der Home-Taste beenden, wird die Anwendung sofort beendet, indem die exit-Systemfunktion mit einem Argument von null aufgerufen wird. " –

1

Nach [Pool-Release] gibt es nichts zu loggen?

+0

diese Theorie sollte einfach zu überprüfen sein, nur vor der Veröffentlichung protokollieren. –

+0

Ich testete es mit einem Debugger vor der Veröffentlichung, um zu verifizieren, dass der Thread die Funktion UIApplicationMain() nie wirklich beendet (d. H. NSLog() wird nie ausgeführt). Wahrscheinlich hätte ich das in der Frage erwähnen sollen. –

1

versucht fprintf und sehen, was

uns geschieht
int main(int argc, char *argv[]) 
{ 
    /* 
     ... 
    same as above 
     ... 
    */ 
    [pool release]; 
    char file_name = "/tmp/log" 

    FILE *file = fopen(file_name, "w"); 

    fprintf(file_name, "END\n"); 
} 

und sagen, was

geschieht

Ich dachte auch der einfachste Weg war zu prüfen, einen Haltepunkt direkt an der Rückkehr zu setzen

in gdb do

b main.c:x 

wo x ist die Zeilennummer der Rückkehr s RKLÄRUNG

+0

Entschuldigung, ich hätte in der Frage erwähnen sollen, dass ich in einem Debugger durch main() gegangen bin, um zu überprüfen, dass der Thread UIApplicationMain() niemals beendet. Es scheint wirklich, dass wenn Sie eine iPhone App stoppen, indem Sie auf die Schaltfläche "Home" klicken, ist das erwartete Verhalten, den Thread vor dem Beenden von main() einfach zu beenden. –

+0

Nun, das bestätigt nur, dass die Theorie von [Pool-Release] das Logggin falsch verhindert. – hhafez

3

Versuchen:

int main(int argc, char *argv[]) 
{ 
    NSLog(@"Step 0"); 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSLog(@"Step 1"); 
    int retVal = UIApplicationMain(argc, argv, nil, nil); 
    NSLog(@"Step 2"); 
    [pool release]; 
    NSLog(@"Step 3"); 
    return retVal; 
} 

Es kann sein, dass die Freigabe des Pools weitere Protokollierung verhindert, in dem Fall, dass Sie Schritt 2 erhalten würden, aber nicht Schritt 3.

Wenn Schritt 2 isn‘ Wenn es gedruckt wird, dann ist mit UIApplicationMain mit Sicherheit etwas nicht in Ordnung - es besteht die Möglichkeit, dass es nicht zurückkehrt, daher NSLog-Anweisungen (Schritt 1.1, Schritt 1.2, ...) an verschiedenen Stellen einfügen und ausführen, um die zuletzt protokollierte Nachricht zu finden .

Nach unten bohren (Schritt 1.7.1, 1.7.2, .... 1.7.6.3.2, ...) - schließlich werden Sie die genaue Linie ausfindig machen (jedoch tief in der Aufrufhierarchie) Wenn die Protokollmeldungen nicht mehr protokolliert werden, ist diese Zeile der Täter (entweder "Protokollierung abbrechen" oder "Beenden", ohne normal zurückzukehren).

Ein weiteres Snippet ich im Web gefunden:

=====

Wenn Sie diese Zeile:

int retVal = UIApplicationMain(argc, argv, @"MyApp", @"MyApp"); 

Die erste MeineAnw Ihr Haupt AppDelegate Klasse. Die zweite ist die Klasse, an die SpringBoard Berührungsbenachrichtigungen sendet.

Auch, wenn Sie das SDK verwenden und eine Hauptnib in der Info definiert haben.plist, dann können Sie den Anruf wie verlassen:

int retVal = UIApplicationMain(argc, argv, nil, nil); 

als alle, die abgedeckt werden, wenn Sie Ihre xibs erstellen.

=====

Jetzt genug Ich weiß nicht, über iPhone Entwicklung (insbesondere xibs) zu wissen, was das letzte Bit auch Mittel (oder, wenn Sie haben es richtig eingerichtet), aber es klingt wie eine weitere Phase der Kompilierung.

Allerdings ist mein erster Gedanke aus dem Lesen, dass Springboard Ihre Delegate-Klasse aufrufen wird, wenn die Tasten gedrückt werden, um Sie zu bitten, etwas zu tun (wie elegant herunterzufahren). Wenn es Sie nicht fragen kann (d. H. Kein Delegierter), liegt es wahrscheinlich in seinem Recht, Sie so herunterzufahren, wie es für richtig hält, wie zum Beispiel mit [UIApplication _terminateWithStatus:].

In der Windows-Welt würden Sie wahrscheinlich eine Quit-Nachricht an das Hauptfenster senden, aber, wie ich schon sagte, iPhone-Entwicklung kann anders sein.

Dennoch ist es eine Möglichkeit, zu untersuchen. Ich wäre daran interessiert zu sehen, welche Anrufe an einen Delegierten gerichtet wurden, wenn Sie einen zur Verfügung gestellt haben. Der Code mit dem Code-Schnipsel enthalten hatte darüber:

@implementation MyApp 
- (void) applicationDidFinishLaunching:(id)unused { 
    rect = [ UIHardware fullScreenApplicationContentRect ]; 
    rect.origin.x = 0.0f; 
    rect.origin.y = 0.0f; 
    window = [ [ UIWindow alloc ] initWithContentRect: rect ]; 
    [ window makeKeyAndVisible ]; 
    view = [ [ MyAppView alloc ] initWithFrame: rect ]; 
    [ window setContentView: view ]; 
} 
- (void) dealloc { 
    [ window release ]; 
    [ view release ]; 
    [ super dealloc ]; 
} 

Also vielleicht ein Delegierter mit dealloc() ist das Geheimnis, um es zurück zu main() zu verlassen. Warum gibst du das nicht ab? Es bringt Sie vielleicht Ihrem Ziel näher, auch wenn es das Kernproblem nicht löst.

+0

Ich hätte erwähnen sollen, dass ich in einem Debugger durch main() gegangen bin, um zu verifizieren, dass der Thread UIApplicationMain() niemals beendet. Das heißt, ich habe auch Ihren Test wegen der Klarheit durchgeführt; "Schritt 2" und "Schritt 3" erscheinen nicht in der Konsole. –

1

Nach dem Aufruf der UIApplicationMain Funktion startet Ihre Anwendung (Einrichten eines Runloops, etc) und alle Arbeiten sollten dann außerhalb des Kontextes von main ausgeführt werden (wenn Sie es in main ausführen müssen, tun Sie es vor diesem Punkt). Beim Beenden einer Anwendung ist es im Allgemeinen effizienter, dem Betriebssystem Speicherbereinigungen zu ermöglichen.

+0

Einverstanden. Mein Anliegen ist jedoch nicht die Freigabe des Pools, sondern die Möglichkeit, dass meine eigene App etwas falsch macht und nicht richtig beendet (basierend auf Apples Dokumentation sollte main() fertig sein). Aber Sie haben einen guten Punkt hinsichtlich der Effizienz beim Herunterfahren/Aufräumen und Vermeiden von Dealloc-Anrufen. –

0

Ich habe das nicht zurück Erfahrung auch. Und ich habe Breakpoints gesetzt, um genau das zu bestätigen, wie Clint gesagt hat.

wisequark hat einen guten Punkt.

großes Thema. Ich fühle mich wohler, dass ich nicht der einzige bin, der die Frage hat.

Verwandte Themen