我认为 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
然后把手机 IP 地址放在 THEOS_DEVICE_IP 环境变量中,这样 theos 才知道安装到哪里,如下:
1
export THEOS_DEVICE_IP=手机IP地址
然后执行 make package install 打包并安装到手机上 (如果 Cydia 在前台,把它退到后台,否则安装会失败):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
➜ firsttweak make package install /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... make[2]: Nothing to be donefor `internal-library-compile'. Making stage for tweak FirstTweak... dpkg-deb:正在新建软件包“com.joeyio.firsttweak”,包文件为“./com.joeyio.firsttweak_0.0.1-2_iphoneos-arm.deb”。 install.exec "cat > /tmp/_theos_install.deb; dpkg -i /tmp/_theos_install.deb && rm /tmp/_theos_install.deb" < "./com.joeyio.firsttweak_0.0.1-2_iphoneos-arm.deb" root@192.168.199.126's password: Selecting previously deselected package com.joeyio.firsttweak. (Reading database ... 6250 files and directories currently installed.) Unpacking com.joeyio.firsttweak (from /tmp/_theos_install.deb) ... Setting up com.joeyio.firsttweak (0.0.1-2) ... install.exec "killall -9 SpringBoard" root@192.168.199.126's password:
安装过程中需要输入两次手机 Root 密码,一次是为了把打包后的 deb 程序文件传到手机上,另外一次是 kill 掉 SpringBoard,使 SpringBoard 重启。
这只是一个简单的 Xcode 插件的入门编写示例,不过 “麻雀虽小,五脏俱全”,可以了解到 Xcode 的插件一些东西,比如 Xcode 插件本质上其实就是一个 Mac OS X bundle 等等,而且因为没有 Apple 官方的文档的支持,很多东西只能去 Google,或者参考别人插件的一些实现。