我正在尝试将游戏库移植到iPhone。与SDL不同,此库不能完全控制您的main()函数,而是通过您自己的代码中的快速返回函数与之通信的。因此,例如,明显的伪代码:

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代码,祈祷它在拆卸期间没有做任何重要的事情。

  • 有什么建议吗?

    最佳答案

    看来我在这里回答自己的问题!在我能够在真实的硬件上对其进行测试并将其放入应用商店之前,我不会接受我的回答。也就是说,我将在此处保留我的最新信息,包括哪些选项不起作用。

    想法#1 :事实证明,每个NSRunLoop都是特定于线程的。如果我在单独的线程中创建UIApplicationMain,则不会收到任何消息。作为副作用,这使得无法确定何时完成初始化,因此,如果有任何非线程安全的功能,它将无法正常工作。我也许可以跨线程向它发送一条消息,以弄清何时完成初始化,但是现在我称之为死胡同。

    想法2 :UIApplicationMain做很多细微的事情。我不确定它的限制,但是如果不涉及UIApplicationMain,我将无法使任何工作。想法2是正确的。

    想法3::接收操作系统信号很重要-您需要知道是否有电话覆盖,或者是否要退出。最重要的是,为了正确启动应用程序,一些设置消息似乎至关重要。我无法找到任何方法来保持消息的发送而无需进入UIApplicationMain。我想到的唯一选项是NSRunLoop和CFRunLoop。两者均无济于事-消息没有按我想要的那样传入。我可能没有使用这些权利,但是在任何情况下,想法3都是可行的。

    全新的疯狂创意#4 :可以在C/C++中使用setjmp/longjmp来伪造协程。诀窍是首先将堆栈指针设置为不会破坏任何重要内容的值,然后启动第二个例程,然后来回跳转,假装您有两个堆栈。如果您的“第二协程”决定从其主函数返回,则事情会变得有些困惑,但是幸运的是,UIApplicationMain从不返回,因此这不是问题。

    我不知道是否有一种方法可以在真正的硬件上显式设置堆栈指针,例如,设置为我动态分配的数据块。幸运的是,没关系。 iPhone默认情况下具有1MB的堆栈,足够容纳几个协程。

    我当前正在做的是使用alloca()将堆栈指针向前推768 KB,然后生成UIApplicationMain,然后使用setjmp/longjmp在“UI例程”和“主例程”之间来回弹跳。到目前为止,这是可行的。

    注意事项:

  • 无法知道“UI例程”何时没有消息要处理,何时没有消息要处理,它将无限期地阻塞,直到情况不再如此。我通过使计时器每0.1毫秒触发一次来解决此问题。每次计时器触发时,我都会退出“主例程”,执行一个游戏循环,然后返回“UI例程”以进行另一个计时器滴答。阅读文档表明它不会无限期地堆积“计时器调用”。我似乎确实得到了“终止”消息,尽管我尚未设法对其进行彻底的测试,并且我也没有测试任何其他重要消息。 (幸运的是,总共只有四条消息,其中一条与安装相关。)
  • 大多数现代操作系统不会一次分配整个堆栈。 iPhone可能就是其中之一。我不知道的是,将meg的堆栈指针3/4向前碰撞是否会分配“它后面”的所有内容。如果是这样,我可能实际上在浪费3/4兆的RAM,这在iPhone上是很重要的。这可以通过将指针向前碰撞较小的数量来解决,但这确实是在困扰堆栈大小灾难-它有效地限制了堆栈,无论您将指针向前碰撞的程度如何,您都必须事先弄清楚这一点。堆栈中的一些标记数据,加上良好的监视和日志记录系统以解决堆栈大小问题,可能可以解决此问题,但这不是一个小问题。 (或者,如果我能弄清楚如何直接在 native 硬件上处理堆栈指针,则只需malloc()/new []几千字节,将堆栈指针指向它,然后将其用作新堆栈即可。我必须弄清楚它需要多少空间,但考虑到它做得并不多,我怀疑会占用多少空间。)
  • 目前尚未在实际硬件上进行测试(给它一两个星期的时间,我有另一个项目要首先完成。)
  • 我不知道苹果在尝试提交到App Store时是否会弄清楚我在做什么,并在上面贴上一个巨大的REJECTED标签。我们应该说,这稍微超出了他们使用API​​的意图。手指交叉。

  • 我会保持最新状态,并在我确认它可以正常工作后正式接受它。

    后期更新:我因其他各种事情而分心。从那时起,我进行了一些更改,使我对Apple开发的兴趣大大降低。我目前的方法没有任何迹象表明它不起作用,但是我真的没有动力继续充实它。对不起!如果我改变主意,将进一步进行更新,但是Outlook不太好。

    10-06 09:20