我认为 run loop 就是较好的利用了这个事实的一种机制。一个 run loop 就是跑在单个线程上进行事件处理的循环。你在 run loop 上注册输入源,并指定当这些源有输入时应该执行的代码。当特定的源上有输入时,run loop 就会执行对应的代码,然后继续等待下一个输入事件。如果在 run loop 正在执行处理代码时,另外一个源的输入到了,run loop 会在执行完正当前的处理后处理这个输入事件。好处是虽然你不知道具体的输入顺序,但你知道它们最终会一个接一个地被串行处理。这就是说你不会遇到多线程的问题,这也是 run loop 非常有用的原因。
和线程的关系?
每个线程,包括应用的主线程都有一个相关联的 run loop 对象,在应用中你不需要显式的创建 run loop 对象。在 Carbon 和 Cocoa 应用中,主线程会自动设置并运行它的 run loop,这个过程也是应用启动过程的一部分。
Run loop 的使用
默认情况下,iPhone 上的所有触摸事件都会被 main run loop 放在队列里等待处理,所以你不需要对 UI 组件做额外的事情,而其他输入源需要一些额外的编码。比如在 run loop 上 schedule 一个 NSInputStream,你需要像下面这样:
那什么时候不适合使用 run loop 呢?根据 run loop 的特点,输入事件会一个接一个的被串行处理,那么如果一个事件的处理需要的时间特别长的话,就会导致在这个事件处理完之前,app 无法响应别的输入事件。在这种情况下,新开一个线程处理更合适。 然而,大部分情况下,我们的代码处理屏幕、socket 或者计时器事件都非常快,这时使用 main run loop 处理起来更简单,也更安全。
安装 Xcode Command Line Tools,可以在命令行下执行 xcode-select --install 来安装或者参考 SO 来安装,安装完之后再进行下一步。
安装 dpkg ,首先安装 MacPorts,可以通过它的官网 , 根据自己的系统版本来选择。安装好之后,重启 Terminal,执行 port version,显示出版本号说明安装成功。如果提示 command not found,尝试在 /etc/paths 文件中加入下面两个路径:/opt/local/bin/opt/local/sbin,需要使用 root 权限来编辑,比如用 Vim 的话:sudo vi /etc/paths. 重启 Terminal,再次输入 port version 就应该会显示版本号了,然后执行 sudo port selfupdate 来更新一下,之后执行 sudo port install dpkg 来安装 dpkg. 安装 dpkg 的目的是把我们写的 tweak 打成 deb 包。
OK,那么我们的第一个 tweak 就创建好了,好像一点也不难啊。进入到 firsttweak 目录下,使用 make 编译一下,可能结果是这样的:
1 2 3 4 5 6 7 8 9 10
➜ firsttweak make /Users/qiaoxueshi/Desktop/mytweaks/firsttweak/theos/makefiles/targets/Darwin/iphone.mk:41: Deploying to iOS 3.0 while building for 6.0 will generate armv7-only binaries. Making all for tweak FirstTweak... Preprocessing Tweak.xm... Name "Data::Dumper::Purity" used only once: possible typo at /Users/qiaoxueshi/Desktop/mytweaks/firsttweak/theos/bin/logos.pl line 615. Compiling Tweak.xm... Linking tweak FirstTweak... Stripping FirstTweak... Signing FirstTweak... /bin/sh: ldid: command not found
这只是一个简单的 Xcode 插件的入门编写示例,不过 “麻雀虽小,五脏俱全”,可以了解到 Xcode 的插件一些东西,比如 Xcode 插件本质上其实就是一个 Mac OS X bundle 等等,而且因为没有 Apple 官方的文档的支持,很多东西只能去 Google,或者参考别人插件的一些实现。