Похоже, я отвечаю на свой вопрос здесь!Я не принимаю мой ответ, пока не смогу одновременно протестировать его на реальном оборудовании и загрузить в магазин приложений.Тем не менее, я буду хранить здесь свою самую актуальную информацию, в том числе о том, какие опции не работали.
Идея # 1 : Оказывается, что каждый NSRunLoop является поточнымконкретный.Если я создаю UIApplicationMain в отдельном потоке, он не получает никаких сообщений.В качестве побочного эффекта это делает невозможным определение того, когда он завершает инициализацию, поэтому, если он выполняет какие-либо функции, не обеспечивающие безопасность потоков, он просто не будет работать.Возможно, я смогу отправить ему сообщение через потоки, чтобы выяснить, когда он завершит инициализацию, но сейчас я называю это тупиком.
Идея # 2 : UIApplicationMain выполняетмного тонких вещей.Я не уверен, чем это ограничено, но я не смог заставить что-либо работать без участия UIApplicationMain.Идея № 2 верна.
Идея № 3 : важно принимать сигналы ОС - вам нужно знать, есть ли наложение телефонных звонков или вы собираетесь выйти,Вдобавок ко всему, некоторые из сообщений настройки кажутся жизненно важными для правильного запуска приложения.Мне не удалось найти какой-либо метод, позволяющий сохранить отправку сообщений, не находясь внутри UIApplicationMain.Единственные варианты, которые я придумал, были NSRunLoop и CFRunLoop.Ни один из них не работал - сообщения не приходили так, как я хотел.Возможно, я не пользуюсь этим правом, но в любом случае Идея № 3 отсутствует.
Совершенно новая сумасшедшая Идея № 4 : можно использовать setjmp / longjmp для подделки сопрограмм вC / C ++.Хитрость заключается в том, чтобы сначала установить указатель стека на какое-то значение, которое не будет мешать чему-либо важному, затем запустите вторую процедуру, а затем прыгайте назад и вперед, делая вид, что у вас два стека.Все становится немного грязно, если ваша «вторая сопрограмма» решает вернуться из своей основной функции, но, к счастью, UIApplicationMain никогда не возвращается, так что это не проблема.
Я не знаю, есть ли способявно установить указатель стека на реальном оборудовании, скажем, на часть данных, которые я выделил на лету.К счастью, это не имеет значения.По умолчанию iPhone имеет 1 МБ стека, что достаточно для размещения нескольких сопрограмм.
В настоящее время я использую alloca (), чтобы переместить указатель стека на 768 килобайт, а затем порождает UIApplicationMain.затем с помощью setjmp / longjmp отскочить назад и вперед между моей «подпрограммой пользовательского интерфейса» и моей «основной подпрограммой».Пока что это работает.
Предостережения:
Невозможно узнать, когда в «подпрограмме пользовательского интерфейса» нет сообщений для обработки и когда нет сообщений дляобрабатывать, он будет просто блокировать на неопределенный срок, пока это не так.Я решаю это путем создания таймера, который срабатывает каждые 0,1 миллисекунды.Каждый раз, когда срабатывает таймер, я выпадаю из своей «основной процедуры», выполняю одиночный игровой цикл, а затем возвращаюсь в «процедуру пользовательского интерфейса» для следующего такта таймера.Чтение документации показывает, что она не будет накапливать «вызовы по таймеру» бесконечно.Мне кажется, что я получаю сообщение «прекратить» надлежащим образом, хотя мне еще не удалось тщательно протестировать его, и я не проверял никаких других важных сообщений.(К счастью, всего четыре сообщения, и одно из них связано с настройкой.)
Большинство современных ОС не выделяют весь стек сразу. IPhone, вероятно, один из них. Чего я не знаю, так это того, что увеличение указателя стека на 3/4 мегабайта вперед выделит все, так сказать, «за ним». Если это так, я могу эффективно тратить 3/4 мегабайта оперативной памяти, что на iPhone очень важно. Эту проблему можно решить, повернув указатель вперед на меньшую величину, но на самом деле это катастрофическое изменение размера стека: оно эффективно ограничивает ваш стек тем, насколько далеко вы поднимаете указатель вперед, и вам придется это выяснить заранее. Некоторые дозорные данные в стеке в сочетании с хорошим мониторингом и системой регистрации проблем размера стека, возможно, могут решить эту проблему, но это нетривиальная проблема. (В качестве альтернативы, если я могу выяснить, как перебирать указатель стека непосредственно на собственном оборудовании, я могу просто выполнить malloc () / new [] несколько килобайт, указать на него указатель стека и использовать его в качестве моего нового стека. Я должен выяснить, сколько места ему нужно, но я сомневаюсь, что это будет много, учитывая, что это не очень много.)
Это в настоящее время не проверено на реальном оборудовании (дайте мне неделю или две, у меня есть другой проект, чтобы закончить первым.)
Я понятия не имею, выяснит ли Apple, что я делаю, и наклею на нее гигантскую ОТКЛОНЕННУЮ наклейку, когда я попытаюсь отправить ее в магазин приложений. Это, скажем так, немного за пределами их намерений по API. Скрестив пальцы.
Я буду обновлять этот пост и официально принимать его, как только проверим, что он работает.
Позднее обновление: меня отвлекло множество других вещей. С тех пор у меня было несколько изменений, которые сделали меня гораздо менее заинтересованным в разработке Apple Мой нынешний подход не показал никаких признаков того, что не работает, но у меня действительно нет мотивации, чтобы продолжать делать это. Сожалею! Если я когда-нибудь передумаю, я обновлю это дальше, но Outlook не так хорош.