2010-02-02 177 views
10

我正試圖將遊戲庫移植到iPhone上。與SDL不同,這個庫不能完全控制你的main()函數,它通過你自己的代碼中的快速返回函數進行通信。因此,舉例來說,明顯的僞代碼:如何從iPhone應用程序中刪除UIApplicationMain?

int main() { 
    library_init(); 
    // game init code here 
    while(we_have_not_quit_the_game) { 
    library_message_loop(); 
    library_init_render(); 
    // render stuff 
    library_end_render(); 
    // update game state 
    } 
    library_shutdown(); 
} 

iPhone使這個困難,因爲它需要你調用不會返回UIApplicationMain功能。在library_init();之後,根本無法回到用戶代碼。

我不相信這是必要的 - 有NSRunLoop據說可以用來處理事件。但是,我不知道UIApplicationMain是否有其他重要的功能。 (請注意,我沒有計劃使用.nib文件,這是我發現UIApplicationMain做的唯一的其他事情。)

我有三個真正的想法,我可以想到,但他們都是一個主要的實施工作,所以我想知道如果有人有這方面的經驗,我燒了一天嘗試註定的想法。

  • 在Init中,產生一個新線程,在該線程中運行UIApplicationMain。要麼通過線程傳遞所有事件(ugh),要麼只是讓UIApplicationMain線程進入睡眠狀態,並在主線程中使用CFRunLoop。我聽說UIApplicationMain不喜歡在不同的線程中運行,但是。
  • 完全忽略UIApplicationMain,只是使用NSRunLoop。我會錯過重要的iPhone設置嗎?誰知道!
  • 使用longjmp()在安裝後跳出UIApplicationMain代碼做一些可怕的事情,並祈禱它在拆卸過程中不做任何重要的事情。

建議?

回答

0

目標是讓main()函數在iPhone上不加修改地工作嗎?

看起來你不可能完全隔離圖書館的用戶從思考iPhone平臺 - 他們將不得不處理XCode的代碼簽名和類似的事情。如果告訴用戶他們必須將他們的main()函數分解成幾個片段,並且您可以從applicationDidFinishLaunching調用並從適當的計時器調用它,但這似乎不會給任何人帶來不便。

+1

排序,是的。更具體地說,我寧願讓用戶完全控制遊戲循環 - 我在引擎庫上構建的引擎已經在Windows和OSX中做了一些非傳統的東西,我想保留這種非常規性。老實說,我想提供這個,不僅僅是爲了允許未修改的main()(儘管這確實是一個很好的好處),但是因爲我認爲它實際上是一個比事件更好,更有用的API佈局驅動佈局iPhone似乎很喜歡。 有時你只需要做一些古怪的東西。 – ZorbaTHut 2010-02-03 00:52:44

0

爲什麼不從UIApplication內部啓動遊戲循環? (是的,你不能在main(),但這不應該。)一些委託消息是很好的候選人。

+3

基本上,這是因爲圖書館試圖接管你的整個執行環境讓我煩惱,而且還會讓圖書館裏的其他人惱火。是的,在仍然控制整個執行環境的同時,確實有辦法做到這一點。我真的寧願避免這種情況。 – ZorbaTHut 2010-02-03 06:11:16

5

看起來我在這裏回答我自己的問題!我不能接受我的答案,直到我能夠在真實硬件上進行測試並將其加入應用商店。也就是說,我會在這裏保留我的最新信息,包括哪些選項無效。

想法#1:事實證明,每個NSRunLoop是線程特定的。如果我在單獨的線程中創建一個UIApplicationMain,它不會收到任何消息。作爲一個副作用,這使得它不可能確定它何時完成初始化,所以如果有任何非線程安全的話,它就無法工作。我可以通過線程發送消息來確定初始化完成的時間,但現在我稱之爲死路一條。

想法#2:UIApplicationMain做了很多微妙的東西。我不確定它僅限於什麼,但是如果不涉及UIApplicationMain,我無法做任何工作。想法#2是正確的。

想法#3:接收操作系統信號非常重要 - 您需要知道是否有電話覆蓋,或者您是否即將退出。最重要的是,爲了正確啓動應用程序,一些設置信息似乎很重要。我無法找到任何方法來保持郵件不在UIApplicationMain中發送。我想出的唯一選擇是NSRunLoop和CFRunLoop。兩人都沒有工作 - 信息沒有像我想要的那樣進來。我可能不會使用這些權利,但無論如何,想法#3已經出來。

全新的瘋狂想法#4:可以使用setjmp/longjmp在C/C++中僞造協程。訣竅是首先將堆棧指針設置爲某個不會破壞任何重要內容的值,然後開始第二個例程,然後來回跳動,假裝你有兩個堆棧。如果你的「第二協程」決定從其主函數返回,事情會變得有點混亂,但幸運的是,UIApplicationMain永不返回,所以這不是問題。

我不知道是否有辦法在真實的硬件上明確地設置堆棧指針,比如說,對我在運行中分配的大量數據。幸運的是,這並不重要。 iPhone默認有一個1MB的堆棧,這很容易適合一些協程。

我現在正在做的是使用alloca()將堆棧指針前進768千字節,然後產生UIApplicationMain,然後使用setjmp/longjmp在我的「UI例程」和我的「主例程」之間來回跳動。到目前爲止,這是行得通的。

注意事項:

  • 這是不可能知道什麼時候「UI程序」有沒有消息來處理,而當它有沒有消息來處理,它只會無限期地阻塞,直到那情況就不一樣了。我正在通過製作一個每0.1毫秒觸發一次的計時器來解決這個問題。每次計時器觸發時,我退出到我的「主程序」,執行單個遊戲循環,然後返回到「UI例程」以獲得另一個計時器記號。閱讀文檔表明它不會無限地累積「定時器調用」。我確實似乎得到了適當的「終止」消息,儘管我還沒有設法徹底測試它,而且我還沒有測試過任何其他重要消息。 (幸運的是,只有四個郵件總數的,其中之一是建立相關的。)

  • 大多數現代操作系統不會在一次分配整個堆棧。 iPhone可能就是其中之一。我不知道的是,向前移動一個meg的堆棧指針3/4是否會分配「後面」的所有內容,可以這麼說。如果是這樣,我可能會浪費3/4的RAM,這在iPhone上是很重要的。這可能是由碰撞的指針向前較小的量來處理,但是這次是真的求婚堆棧大小災難 - 它有效地限制你的堆棧但遠你碰到前面的指針,你必須事先想出解決辦法。堆棧中的一些標識數據,加上良好的監控和針對堆棧大小問題的日誌記錄系統,可能可以解決這個問題,但這是一個不容忽視的問題。 (或者,如果我能弄清楚如何在本地硬件上直接使用堆棧指針,我可以將malloc()/ new []指定爲幾千字節,將堆棧指針指向它,並將其用作我的新堆棧。我必須弄清楚它需要多少空間,但是我懷疑它會很多,因爲它沒有太大的作用。)

  • 這是目前未在實際硬件上測試的(給它一個星期或兩個星期,我還有另一個項目先完成。)

  • 當我嘗試提交給應用程序商店時,我不知道蘋果是否會弄清楚我正在做什麼,併爲它拍攝一個巨大的拒絕貼紙。這是,我們應該說,略微超出他們對API的意圖。手指交叉。

我會保留這篇文章的更新內容,並且一旦我確認它已經被正式接受,你知道,它會起作用。

最新更新:我被各種其他事情分心了。從那以後,我做了一些改變,使我對蘋果開發的興趣減少了。我目前的做法顯示沒有跡象,但沒有工作,但我沒有真正的動力來保持充實。抱歉!如果我改變主意,我會進一步更新,但Outlook不太好。

+0

幾乎肯定你會被拒絕。 Bummer,但應用程序因爲使用標準API之外的單一方法而遭到拒絕,所以以任何方式顛覆它都可能是不行的。 – typeoneerror 2010-02-07 02:19:58

+0

這就是訣竅 - 雖然我沒有使用API​​以外的任何東西,但我使用的每個函數都是100%支持並允許的。我只是重新安排了一下。如果不實際拆解代碼庫,應該完全無法檢測到這一點。 – ZorbaTHut 2010-02-08 07:04:04

+1

FWIW,回答你自己的問題是非常好的,如果沒有其他人可以,並且你在一段時間後弄清楚,那麼這是一個很好的補充(和接受的練習)。 – 2010-02-08 08:15:05

1

我知道NSApplicationMain() Info.plist中讀取並執行的東西到應用程序(如獲得初始筆尖文件),所以我猜想,UIApplicationMain()做同樣的iPhone(如獲得初始的狀態欄樣式,縮放爲Default.png圖像等)。這些東西沒有暴露在其他地方,所以它調用的函數仍然需要運行,才能啓動應用程序以避免任何副作用。你唯一的選擇就是逆向工程並複製它們(並且希望他們所做的任何事都在公共SDK中)。

+0

我們在哪裏可以找到這個函數的源代碼? 我有一個類似的問題 - 我想編寫一個沒有UI的iPhone應用程序 - 似乎大多數的SDK(例如NSFileManager)沒有UIApplicationMain工作....任何想法如何實現? – 2011-12-18 08:04:31

相關問題