2009-02-18 3 views
9

Рассмотрим следующий main() метод, который вы найдете большинство приложений картинки:Почему функция main() приложения iPhone никогда не имеет возможности закончить?

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

В каждом iPhone приложение, которое я запустить в симуляторе с ними (в том числе несколько примеров проектов, предусмотренных Apple), поток никогда не выходит из UIApplicationMain() и любой оставшийся код в main() никогда не выполняется. Это ожидаемое поведение?

Я проверил, что заявления после UIApplicationMain() никогда не запускаются, переходя через код с помощью отладчика. Когда пользователь останавливает приложение (например, нажав кнопку «Главная»), итоговая трассировка стека показывает, что в конечном итоге вызывается [UIApplication _terminateWithStatus:]. Эта функция вызывает метод делегата вашего приложения applicationWillTerminate:. Как только это завершается, [UIApplication _terminateWithStatus:], кажется, убивает/выходит из потока.

Может кто-нибудь подтвердить, что это должно быть так, как должно работать main() или хотя бы подтвердить такое же поведение на своей машине?

ответ

19

Оригинальный вопрос: «Почему главная функция не является iPhone приложения в() когда-либо получить шанс закончить

Короткий ответ: Потому что UIApplicationMain() кодируется так, что он никогда не возвращается ,

После выполнения нескольких тестов в симуляторе и на устройстве и попросив другого разработчика выполнить те же тесты, я подтвердил, что UIApplicationMain никогда не возвращается. Когда пользователь обычно заканчивает приложение, нажав кнопку «Домой», программа в конечном итоге завершается внутри неопубликованного метода UIApplication, называемого _terminateWithStatus. Этот метод вызывает exit (0).

Это поведение соответствует функции NSApplicationMain (это версия AppKit/Cocoa функции UIApplicationMain). В документации для NSApplicationMain() четко указано, что она никогда не вернется.

Я отправил Apple ошибку (6600198), в которой испрашивается официальная документация (и шаблон Xcode для main.m), чтобы указать, что UIApplicationMain() никогда не возвращается. Хотя это не является функциональной проблемой, текущий шаблон и документы вводят в заблуждение.

Спасибо всем за вход и мозговой штурм!

+2

Обновление: я рад сообщить, что Apple изменила официальную документацию для UIApplicationMain() и закрыла мою ошибку. Документация теперь включает следующее: Несмотря на то, что задан тип возвращаемого целого числа, эта функция никогда не возвращается. Когда пользователи завершают приложение iPhone, нажав кнопку «Домой», приложение сразу же выйдет, вызвав системную функцию выхода с аргументом нуля ». –

1

После [пула релиза] нечего входить в систему?

+0

, что теория должна быть легко проверена, просто зарегистрируйтесь перед выпуском. –

+0

Я тестировал его с помощью отладчика перед отправкой, чтобы убедиться, что нить никогда не выходит из функции UIApplicationMain() (т. Е. NSLog() никогда не выполняется). Вероятно, следовало бы упомянуть об этом в вопросе. –

1

пытается с помощью fprintf и посмотреть, что происходит

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

и сказать нам, что происходит

Я также думал, что самый простой способ проверить, был установить право точки останова при возврате

в gdb do

b main.c:x 

где x - номер строки возврата s tatement

+0

Извините, я должен был упомянуть в вопросе, что я прошел через main() в отладчике, чтобы убедиться, что нить никогда не выходит из UIApplicationMain(). По-видимому, когда вы останавливаете приложение для iPhone, нажав кнопку «Главная», ожидаемое поведение - просто убить поток до выхода main(). –

+0

хорошо, что просто подтверждает, что теория [пула релиза] предотвращает ложную ложь. – hhafez

3

Try:

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

Это может быть, что освобождение бассейна предотвращения дальнейшего протоколирования и в этом случае вы получите шаг 2, но не шаг 3.

Если шаг 2 ISN» t, то это почти что-то не так с UIApplicationMain - есть вероятность, что он не вернет так, что он поставит NSLog-инструкции (шаг 1.1, шаг 1.2, ...) в разных точках внутри него и запустится, чтобы найти последнее сообщение в журнале ,

Продолжайте сверление (шаг 1.7.1, 1.7.2, .... 1.7.6.3.2, ...) - в конечном итоге вы будете отслеживать точную линию (хотя бы глубину иерархии вызовов) когда сообщения журнала перестают регистрироваться, и эта строка будет вашей виновницей (либо «выключение» протоколирования, либо выход, не возвращаясь нормально). далее

Один фрагмента я нашел в Интернете:

=====

При использовании этой линии:

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

Первый MyApp Ваш главный класс приложение делегат. Второй - это класс, в котором SpringBoard отправляет уведомления о касании.

Также, если вы используете SDK и имеете главный наконечник, определенный в Info.PLIST, то вы можете оставить вызов как:

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

как все это будет покрыта, когда вы создаете свои xibs.

=====

Теперь я не знаю достаточно о развитии iPhone (специально xibs), чтобы знать, что это последний бит даже средства (или, если вы установите его правильно), но это звучит как другой этап компиляции.

Однако, моя первая мысль от чтения заключается в том, что Springboard вызовет ваш класс делегата, когда кнопки будут нажаты, чтобы попросить вас что-то сделать (например, закрыть изящно). Если он не может спросить вас (т. Е. Ни один делегат), вероятно, это право на то, чтобы закрыть вас, как он считает нужным, например, с [UIApplication _terminateWithStatus:].

В мире Windows вы, вероятно, отправите сообщение о выходе в главное окно, но, как я уже сказал, разработка iPhone может быть разной.

Тем не менее, это авеню для расследования. Мне было бы интересно узнать, какие призывы были сделаны делегату, если вы предоставили его. Код, включенный с сниппета выше было это:

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

Так может быть, делегат с dealloc() секрет заставить его выйти обратно main(). Почему бы тебе не сделать это? Это может приблизиться к вашей цели, даже если это не решит основную проблему.

+0

Я должен был упомянуть, что я прошел через main() в отладчике, чтобы убедиться, что нить никогда не выходит из UIApplicationMain(). Тем не менее, я также провел ваш тест ради ясности; «Шаг 2» и «Шаг 3» не отображаются в консоли. –

1

После вызова функции UIApplicationMain ваше приложение запускает (установление runloop и т. Д.), И вся работа должна выполняться вне контекста main (если вам нужно, чтобы он запускался в основном, делайте это до этой точки). При выходе из приложения обычно более эффективно разрешать ОС выполнять очистку памяти.

+0

Согласовано. Однако моя забота заключается не в том, что релиз пула, но с возможностью того, что мое приложение делает что-то неправильно и не заканчивается правильно (на основе документов Apple, main() должен закончить). Но у вас есть хорошая точка в отношении эффективности выключения/очистки и избежания вызовов dealloc. –

0

У меня есть опыт не возврата. И установили точки останова, чтобы точно проверить, как сказал Клинт.

wisequark имеет хорошую точку.

отличная тема. заставляет меня чувствовать себя более комфортно, что я не единственный, у кого есть вопрос.

Смежные вопросы