2010-02-02 176 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

相关问题