2009-02-18 13 views
9

Rozważmy następujący main() metody, które można znaleźć najbardziej aplikacje iPhone:Dlaczego funkcja main() aplikacji na iPhone'a nie ma szansy ukończyć?

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

w każdej aplikacji iPhone, że Zabrakło mi w symulatorze z nich (w tym kilka przykładowych projektów dostarczonych przez Apple), wątek nigdy nie wychodzi UIApplicationMain() a pozostały kod w main() nigdy nie zostanie wykonany. Czy to oczekiwane zachowanie?

Sprawdziłem, że oświadczenia po UIApplicationMain() nigdy nie są uruchamiane przez przejście przez kod za pomocą debuggera. Gdy użytkownik zatrzyma aplikację (na przykład poprzez naciśnięcie przycisku "Home"), wynikowy ślad stosu wskazuje, że ostatecznie zostanie wywołana [UIApplication _terminateWithStatus:]. Ta funkcja wywołuje metodę delegata Twojej aplikacji applicationWillTerminate:. Gdy to się skończy, wydaje się, że [UIApplication _terminateWithStatus:] zabija/znika z wątku.

Czy ktoś może potwierdzić, że w ten sposób ma działać main() lub przynajmniej potwierdzić to samo zachowanie na swoim komputerze?

Odpowiedz

19

Oryginalny pytanie było: „Dlaczego główną funkcją nie aplikacja iPhone() kiedykolwiek dostać szansę, aby zakończyć?”

Krótka odpowiedź: Bo UIApplicationMain() jest kodowana taki, że nigdy nie powróci .

Po wykonaniu kilku testów w Symulatorze i na urządzeniu oraz poproszeniu innego programisty o wykonanie tych samych testów, potwierdziłem, że UIApplicationMain nigdy nie wraca. Kiedy użytkownik kończy normalnie aplikację przez naciśnięcie przycisku Home, program ostatecznie kończy się nieopublikowaną metodą UIApplication o nazwie _terminateWithStatus. Ta metoda wywołuje wyjście (0).

To zachowanie jest zgodne z funkcją NSApplicationMain (która jest wersją AppKit/Cocoa funkcji UIApplicationMain). Dokumentacja dla NSApplicationMain() wyraźnie stwierdza, że ​​nigdy nie powróci.

Złożyłem błąd (6600198) do Apple z prośbą o poprawienie oficjalnej dokumentacji (i szablonu Xcode dla main.m), aby stwierdzić, że UIApplicationMain() nigdy nie zwraca. Chociaż nie jest to problem funkcjonalny, bieżący szablon i dokumenty są mylące.

Dziękuję wszystkim za wkład i burzę mózgów!

+2

Aktualizacja: Z przyjemnością informuję, że Apple zmodyfikował oficjalną dokumentację dla UIApplicationMain() i zamknął mój błąd. Dokumentacja zawiera teraz następujące elementy: Mimo że podano typ liczby całkowitej, ta funkcja nigdy nie jest zwracana. Kiedy użytkownicy kończą aplikację na iPhone'a naciskając przycisk Home, aplikacja natychmiast wychodzi, wywołując funkcję systemu wyjścia z argumentem zero. " –

1

Po zwolnieniu puli nie ma nic do zalogowania?

+0

że teoria powinna być łatwa do sprawdzenia, wystarczy zalogować się przed wydaniem. –

+0

Przetestowałem go za pomocą debuggera przed opublikowaniem, aby sprawdzić, czy wątek nigdy naprawdę nie opuszcza funkcji UIApplicationMain() (tzn. NSLog() nigdy nie jest wykonywany). Prawdopodobnie powinien o tym wspomnieć w pytaniu. –

1

próbując przy użyciu fprintf i zobaczyć co się dzieje

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"); 
} 

i powiedz nam, co się dzieje

Myślałem także najprostszy sposób na sprawdzenie było ustawić prawo Point Break w zamian

w gdb do

b main.c:x 

gdzie x to numer wiersza powrotu s tatement

+0

Przepraszam, powinienem był wspomnieć w pytaniu, że przeszedłem przez main() w debugerze, aby sprawdzić, czy wątek nigdy nie opuszcza UIApplicationMain(). Wygląda na to, że po zatrzymaniu aplikacji na iPhone'a przez naciśnięcie przycisku "Home" oczekiwane zachowanie polega na zabiciu wątku przed zakończeniem main(). –

+0

dobrze, że tylko potwierdza, że ​​teoria [uwolnienia puli] uniemożliwia fałszywe logggin. – hhafez

3

Spróbuj:

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; 
} 

może się okazać, że zwolnienie z basenu uniemożliwia dalsze rejestrowanie w takim przypadku można dostać krok 2, ale nie Etap 3.

Jeśli krok 2 ISN” t jest drukowany, to prawie na pewno jest coś nie tak z UIApplicationMain - jest szansa, że ​​nie powróci, więc umieść instrukcje NSLog (krok 1.1, Krok 1.2, ...) w różnych punktach w nim i uruchom, aby znaleźć ostatnią zarejestrowaną wiadomość .

Kontynuuj wiercenia w dół (krok 1.7.1, 1.7.2, .... 1.7.6.3.2, ...) - w końcu wyśledzisz dokładną linię (jakkolwiek głęboko w hierarchii połączeń) kiedy logi przestaną być rejestrowane, a ta linia będzie Twoim winowajcą ("wyłączenie" logowania lub wyjście bez powrotu).

Jedno dodatkowe fragment znalazłem w internecie:

=====

Podczas korzystania z tej linii:

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

Pierwszy MojaApl jest głównym klasa app delegata. Druga to klasa, do której SpringBoard wysyła powiadomienia dotykowe.

Ponadto, jeśli używasz zestawu SDK i masz główną końcówkę zdefiniowaną w Info.plist, wtedy możesz zostawić połączenie jako:

jako wszystko, co będzie objęte przy tworzeniu twoich Psów.

=====

Teraz nie wiem wystarczająco dużo o rozwoju iPhone (konkretnie xibs), aby wiedzieć, co to ostatni bit nawet środki (lub jeśli już ustawić go poprawnie), ale to brzmi jak kolejna faza kompilacji.

Jednak moja pierwsza myśl z czytania polega na tym, że Springboard wywoła twoją klasę delegatów, gdy przyciski będą przyciśnięte, aby poprosić cię o zrobienie czegoś (np. Zamknięcie z wdziękiem). Jeśli nie może Cię zapytać (tj. Nie ma delegata), prawdopodobnie w ramach przysługujących Ci uprawnień może zamknąć Cię według własnego uznania, na przykład za pomocą [UIApplication _terminateWithStatus:].

W świecie Windows prawdopodobnie wyślesz wiadomość do głównego okna, ale, jak mówię, rozwój iPhone'a może być inny.

Mimo to jest to sposób na zbadanie sprawy. Chciałbym zobaczyć, jakie połączenia zostały wykonane z delegatem, jeśli je dostarczyłeś. Kod dołączony do fragmentu powyżej miał to:

@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 ]; 
} 

Więc może delegat z dealloc() jest kluczem do coraz to aby wyjść z powrotem do main(). Dlaczego nie oddasz tego strzału? Może zbliżyć Cię do celu, nawet jeśli nie rozwiąże podstawowego problemu.

+0

Powinienem wspomnieć, że przeszedłem przez main() w debugerze, aby sprawdzić, czy wątek nigdy nie opuszcza UIApplicationMain(). To powiedziawszy, przeprowadziłem także twój test dla jasności; "Krok 2" i "Krok 3" nie pojawiają się w konsoli. –

1

Po wywołaniu funkcji uruchamianie aplikacji (ustanawianie pętli itp.) I cała praca powinna być wykonana poza kontekstem głównym (jeśli potrzebujesz, aby działał w trybie głównym, zrób to przed tym punktem). Podczas zamykania aplikacji zazwyczaj bardziej wydajne jest zezwolenie systemowi na czyszczenie pamięci.

+0

Uzgodnione. Moją obawą nie jest jednak udostępnianie puli, ale z możliwością, że moja własna aplikacja robi coś złego i nie kończy poprawnie (na podstawie dokumentacji Apple'a, main() powinien się skończyć). Ale masz dobry punkt dotyczący skuteczności zamykania/czyszczenia i unikania wywołań dealloc. –

0

Mam to również nie wracam. I ustaw punkty przełamania, aby zweryfikować dokładnie tak, jak powiedział Clint.

wisequark ma dobry punkt.

świetny temat. sprawia, że ​​czuję się bardziej komfortowo, że nie jestem jedynym, który ma pytanie.

Powiązane problemy