关于C++和Objective-C混编

Objective-C在大部分情况下足够满足我们的需求,但是还是会有一些情况必须要使用C++,比如:

  1. 使用C++的库
  2. 当Objective-C不够快的时候

第一点自然不必多说,至于第二点,Objective-C的消息机制比起函数调用还是比较慢的,当对性能有极高要求的时候,就需要C/C++来替代。

C++与Objective-C混编只要注意将包含C++代码的.m文件改为.mm即可,XCode就会自动判断该使用何种编译器来编译。

这看起来简单,但实际操作中还是很容易出现令人费解的编译问题,比如最经典的"Unknow type name ‘class’; did you mean ‘Class’?“。究其原因就是我们没有遵守这两条规则:

  • .m文件不能含有C++代码
  • .m文件所import或include的.h文件中不能直接或间接包含C++代码

在保证你的C++代码是正确前提下,如果发现相关编译错误可以通过如下几个方法修复

  1. 将.h文件中的c++代码转移到其他地方
  2. 阻段include或import链
  3. 将相关的.m文件后缀改成.mm

显然第三种方法相对于前两种实施起来更方便,但如果你使用XCode 4以及之后的版本所包含的模板建立项目的话有可能会忽视一个问题:

当你在AppDelegate.h中include或import一个C++的头文件时,当然你一定不会忘记修改AppDelegate.m为AppDelegate.mm,如果只做了这点儿还不够,我们还忽略了隐藏在Supporting Files组内的一个文件的存在–main.m

在以前的XCode模板中main.m默认是这样的

#import ;

int main(int argc, char *argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

而新的模板是这样的:

#import ;

#import "AppDelegate.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

看出问题来了吧,main.m新增了#import “AppDelegate.h",这就导致了main.m作为一个Objective-C源文件却引入了C++代码,而Xocde会使用Objective-C的编译器进行编译,从而产生编译错误,因此我们还需要将main.m的后缀改成.mm。

总结+吐槽:我在发现main.m这个问题之前对编译错误纠结了好久,一度修改代码,也一度怀疑是XCode本身的问题(XCode 4出奇的不稳定让人不得不对其产生质疑,虽然这次是我错了),希望同样使用Objective-C++的同学不要像我一样栽在main.m上。

–以上–

[iOS]开源控件GSBookShelf–iBooks风格书架实现

GSBookShelf是我参照iBooks的操控实现的一个书架界面(或者说是控件)。项目放在github上了,大家可以去参考。

由于前两天GSBookShelf被Cocoa Controls收录了(不知道谁给我提交上去了,或者他们编辑自己发现的),而且还获得了Control of the week称号,所以有必要提供一个github之外的反馈平台吧。

演示:

效果图(图片比较大,请耐心等待):

imageimageimage

视频演示(感谢Cocoa Controls制作):

u2b

简介:

看过上面效果图并且用过iBooks的同学应该清楚这个控件的基本功能了吧,就是实现书籍拖拽(支持拖拽的同时ScrollView滚动),批量添加,批量删除,以及这些动作的相应动画。

部分功能实现细节:

  • 整体采用了类似UITableView的cell,重用等机制
  • 在拖拽的同时ScrollView滚动是通过NSTimer每隔0.xx秒触发,让ScrollView的contentOffset加1实现的,这种方法看起来可能不太靠谱,但实测性能上没有问题,2代touch上滚动速度略慢。

其他说明:

  • 别忘了开ARC
  • demo中的“书”(bookView)是UIButton,可以替换成任意UIView,只要你别拦截长按手势。
  • 为你自定义的bookView,和cell添加GSBookView和GSBookShelfCell协议来支持重用,这个对性能很重要。
  • 超出书架拖动范围,在书架顶部之上可以添加一个自定义的UIView来实现ibooks中那个苹果图表的效果,在书架底部之下也可以添加一个自定义的UIView来显示出更多层,防止直接显示scrollview的背景的突兀。
  • 在书架顶部可以加一个自定义UIView,demo中我添加了一个UISearchView,可以用来查询
  • “书”(bookView)的尺寸是固定的,如果你希望有所变化,可以把一个透明的UIView设置成bookView,然后在这个view之上添加你的内容,但是手势识别仍旧以透明的UIView的范围为基准,这个问题主要是为了权衡bookView的可定制性,以及实现的难度所做出的妥协。
  • 横屏的图片我没做,原因一是比较懒,二是如果你用这个控件应该会自己作图,三是考虑到下面TODO中提到的内容。

TODO:

  • 在之前一版的demo中虽然支持了横竖屏切换,但是只是简单地reload了一次,而且跳到了书架顶部,细节不太完美,而iBooks在旋转过程中还有一些动画等细节功能,这个会在以后添加,但肯定不是最近(目前比较忙)。

总结:

感谢Cocoa Controls收录,欢迎各位批评指正,如有问题请回复或者通过各种可能的方式联系我。

PS:我无节操地在github项目那里加了个Donate,欢迎支持!

–以上–

[iOS]分享最近发现的一些好东西(120311)

好久没更新了,最近在鼓捣一些Core Audio的有关内容,加上各种事儿,没有时间写东西,先把最近发现的一些好东西分享出来吧。

文章

项目

[iOS]借助VoiceOver来破解优秀App的实现方式

为了开发出更好的iOS App,我们经常会去破解(我更喜欢叫Hack)优秀的App的实现方式,一般我们做的无非就是拆了ipa包浏览一下App所用到的图片资源,找个抓包工具看看都访问了那些网络资源,更虎点的就是去反编译,当然最基础的就是把玩一下各个功能,凭经验看出实现方法。

今天就介绍一个比较另类的Hack方式——VoiceOver,估计大部分人都没在自己的iOS设备上打开过这个功能,我就简单说一下效果吧,更细节的东西还是要各位亲身体验一下。

VoiceOver需要在:通用 >> 辅助功能 >> VoiceOver 页面里开启,打开后会进入一个相对比较难操作的环境,随着手指在屏幕上移动,会有一个黑框附着在手指附近的UI元素上面,同时随着黑框的移动,iOS设备会自动朗读UI元素的内容,不难发现VoiceOver这个黑框具有以下几个特性:

  1. 黑框所在位置就是当前UI元素的真实边框
  2. 对于一些元素比如UIButton,当黑框附着在起上面时,系统就会朗读“xxxxx按钮”,对于UITableView更是可以朗读出当前所在行号,以及一共有多少行。朗读的内容通常包含了这些UI元素的独有特性。
  3. 由于大部分的App都不会对“辅助功能”有所支持,有些没有文字的UI元素系统甚至会朗读其变量名,这跟反编译已经比较相似了。

借助第一个特性我们可以破解App的UI布局,借助第二个特性我们可以找出一些UI元素的实现方式,比如有些Gird View就是用UITableView实现的,如果系统朗读了行号等UITableView所具有的特征内容,我们就可以基本确定这个Gird View就是用TableView来实现的,TabBar之类的也是如此。借助第三条特性,我们可以通过其变量名判断其功能和实现方法。此外对于那些开源应用,变量名也可以方便我们更快地研究开源代码。

相对的,如果我们想避免App的关键实现细节被破解,就要在代码中加入防止VoiceOver响应的代码。

综上,虽然VoiceOver属于辅助功能范畴,但其一些特性为我们Hack App提供了方便。在一般的应用中加入Accessibility支持可能会使开发成本有所提高,但对于某些领域的应用,Accessibility支持无疑会成为应用的一大两点,在此也推荐大家看一下 WWDC 2011 Session 127 – Design Patterns to Simplify Mac Accessibility,真的挺有爱的。

–以上—

Xcode 4.3+ NSLog中文不输出Bug及解决方法

这个Bug折腾了我近一天,读一个文件,NSLog输出文件内容,结果死活读不完整,不光中文没有,英文也不全,考虑了编码,文件大小,文件位置等各种可能的因素,尝试用各种方式重写这个操作,最后发现是NSLog的问题,跟文件一毛钱关系都没有,感谢这两个链接:link1 link2 。

鉴于第二个链接已经解释的很清楚了,我这里就简要说一下,毕竟Wall还是有些麻烦

重现Bug很简单,Xcode 4.3+,用lldb在真机上运行(模拟器没有问题)下面代码:

NSLog(@"English1");
NSLog(@"中文");
NSLog(@"English2");

中文那行神马都不输出啊!如果NSLog一个NSString,String里面有中文,那么输出也会悲剧。

解决方法两种:

  1. 如果你执着于lldb,那么用Organizer >> Devices >> 你的设备 >> Console 这里会显示中文
  2. 按住Option点Run(或者 Product >> Edit Scheme…),Info >> Debugger 设置为GDB

一切回归正常,WTF!

另外有人说4.3.2解决了这个问题,事实是:没有解决!

祝愿被这个问题折腾死的人能早日看到这篇文章或者link2那篇文章。

Becareful with XCode!!

–以上–

XCode 4.3.1一个小众Bug及解决方法

哦… 首先希望闲来无事发现此文的人,可以回复报下你们一天中XCode Crash的次数,附上版本,大家比比谁受气受得多。(我:4.3.1 10多次crash)

目前测试Bug的环境:XCode 4.3.1,用svn作为版本控制
PS. 4.3可能也有这个Bug,4.2.1貌似没有,但不排除svn下的其他毛病

Bug产生过程:

  1. Project处于svn版本控制之下
  2. (可有可无)向Project中添加文件,并加入版本控制(A)
  3. 从项目中Delete某个文件,并选择Move to trash
  4. 编译的时候会有Wraning提示缺少了之前删除的那个文件(Missing File xxxx)

虽然这是一个误报,对编译没有任何影响,但是有Warning看着就心烦,而且如果删除了很多文件就会造成满屏Warning,既影响心情,又影响工作。

下面是几种解决方法

  1. 如果你对XCode 4.3+移植抱有敌视态度,那么你的/Developer或者废纸篓里面可能还有XCode 4.2.1,用4.2.1进行删除的步骤,那些Warning就不会出现。
  2. 完全用XCode 4.3.1 + Terminal解决
    1. 对那些你要删除的并且有"A"(版本控制)标记的文件,右键 >> Source Control >> Discard Changes…
    2. 右键 >> Source Control >> Ignore
    3. Delete并Move to trash

这样编译就不会有warning,如果你删除的是一个文件夹,那么还会提示Missing这个文件夹,再或者上一步删除文件之前忘记设置ignore了,warning就会出现,用终端解决:
1. 打开终端,cd到项目主目录下
2. svn status,可以看到那个Warning的文件(夹)
3. svn rm xxxxx 从版本控制里去掉那个文件(夹)

这时再编译就不会有那个warning了,世界终于清净了

总结:XCode 4+对svn支持非常废,经常有莫名其妙错误,要手动解决,所以一个更方便的方法就是不用svn,现在git这么火,不怕开源的项目就直接放到github上得了,保密的就放到Bitbucket上,或者找个服务器自己搭一个,总比折腾svn这些破事好,不过广大开发者最终还是应该鄙视苹果的,照这么下去苹果还是回到几年前的小众状态比较好,那时无论是SL,还是Xcode 3都是精品中的精品。现在苹果到了风口浪尖上,做东西都很浮躁,各种神奇,傻X的Bug层出不穷,老乔也不托梦骂他们几句。

懒得喷了,话说中午写的这篇,晚上发的,发现XCode 4.3.2出了,不知道老乔显灵没,如果还Crash记得上App Store评一星啊!link

更新:恭喜,XCode 4.3.2下这个Bug依旧

–以上–

iPad 3 图片解压缩测试

之前翻译过Avoiding Image Decompression Sickness[iOS]如何避免图像解压缩的时间开销,现在iPad 3出了,原文也有了后续iPad 3 Image Decompression Benchmarked,所以我也就简单再翻译个后续,推荐先看一眼之前那篇,以下内容都是建立在之前的基础上的。

此次原文没有太多重要内容,挑重点简要翻译,括号内大部分是我的注释,少部分原文,很好辨别。

iPad !!!(iPad 3,这是跟k-on!!或者working!!学的么?),根据GeekBench测试,CPU几乎没有变化(因为A5X只是显卡4核心,CPU还是和iPad 2一样),根据GLBenchmark的结果,苹果对iPad 3做了很大优化,是的在Retina屏幕上的祯数几乎和iPad 2相同。

一位Australia的同学帮忙在他的iPad 3上帮我们运行了benchmark,并把测试结果发给了我们。(之前的结果参考之前的那篇文章,我就不贴图了)

我们预想iPad 3解压缩速度将是iPad 2的2-4倍,iPad 2默认的launch image需要100ms来解压缩并显示,如果在iPad 3上也有相同的速度就可以了。

测试结果如下

PNG Crushed, 1024*768 (init+decode+draw)

  • iPad 2: 5 ms + 89 ms + 18 ms = 113 ms
  • iPad 3: 1 ms + 50 ms + 18 ms = 69 ms

-47%

JPG 80%, 1024*768 (init+decode+draw)

  • iPad 2: 2 ms + 32 ms + 18 ms = 52 ms
  • iPad 3: 2 ms + 32 ms + 17 ms = 51 ms

-2%

PNG Crushed, 2048*1536 (init+decode+draw)

  • iPad 2: 5 ms + 266 ms + 96 ms = 368 ms
  • iPad 3: 2 ms + 171 ms + 66 ms = 238 ms

-33%

JPG 80%, 2048*1536 (init+decode+draw)

  • iPad 2: 1 ms + 121 ms + 69 ms = 192 ms
  • iPad 3: 1 ms + 122 ms + 66 ms = 189 ms

-2%

粗略看下我们发现iPad 3的速度并没有我们预想的那样有4倍的提升。退一步讲,iPad 3的效率的确像Apple描述的那样有2倍的提升(-50%)(A5X比A5显卡快了一倍),但这仅仅针对处理PNG Crushed的情形(-47%),在处理JPEG的时候速度仅仅提高2%,这点儿提升也许是来自SSD读取速度的提升,看起来苹果的开发人员似乎都将JPEG遗忘了。

至于"感觉上" iPad 3是不是比iPad 2快了呢?

恐怕不是,iPad 2显示launch image要113ms,iPad 3上却要消耗238ms,如果没有任何优化的话,一个应用启动要多消耗125ms(记住CPU性能是相同的)。

因此最大的问题就是,杂志类应用开发者更期望这种“感觉上”的速度提升,而实际上即使使用80%全屏大小的JPEG也只能得到5-19(128ms-52ms)的祯数,这就导致了如果在主线程绘制图片,从一个页Scroll到下一个页时就会产生一个明显的卡顿。

总结

现在我们知道为什么新的核心命名为A5X了,这仅仅是与A5相同的CPU配上了一个性能稍高点的显示核心。这个“X”我们计算出来大概为1.4,但仅仅针对PNG,对于JPEG,也许在下一个iOS更新中体现吧。

目前发生这种情况的原因很可能是这样:针对JPEG图片的硬件加速处理模块因为某种情况在iOS 5.1中被遗忘了,或者干脆没有准备好。如果事实果真如此,那么对于苹果来说这真的很尴尬。

最后一段原文打广告。大概就是建议用大图的人暂时只留下必须的小图片,使用他们做的DTCoreText来渲染富文本(蛋疼核心文本?LOL)。(要我说按苹果这么个折腾法矢量图才是王道啊!)

–以上–

[iOS]在运行时为类添加方法

Obj-C用起来真是各种happy,比如现在有这样一种情况:有一个类,我们希望它能响应一个消息(message),但是这个类没有相应的方法(method),而你又偏偏不能重写/继承这个类。这时我们可能会想到,能不能动态地给类添加一个方法呢?感谢Obj-C,仅需简单几步就能实现。

先看一段代码

#if TARGET_IPHONE_SIMULATOR
#import 
#else
#import 
#import 
#endif

@interface EmptyClass:NSObject

@end

@implementation EmptyClass

@end

void sayHello(id self, SEL _cmd) {
    NSLog(@"Hello");
}

- (void)addMethod {
    class_addMethod([EmptyClass class], @selector(sayHello2), (IMP)sayHello, "[email protected]:");

    // Test Method
    EmptyClass *instance = [[EmptyClass alloc] init];
    [instance sayHello2];

    [instance release];

}

我们首先定义了一个EmptyClass,继承NSObject,没有任何自带方法,接着定义了一个函数。这里提一句,Obj-C的方法(method)就是一个至少需要两个参数(self,_cmd)的C函数,这个函数仅仅输出一句Hello。接下来在addMethod方法中,我们调用class_addMethod()为EmptyClass添加方法,class_addMethod()是这样定义的:

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

参数说明:

cls:被添加方法的类

name:可以理解为方法名,这个貌似随便起名,比如我们这里叫sayHello2

imp:实现这个方法的函数

types:一个定义该函数返回值类型和参数类型的字符串,这个具体会在后面讲

接着创建EmptyClass的实例,调用sayHello2,运行,输出Hello,添加方法成功。

接下来说一下types参数,
比如我们要添加一个这样的方法:-(int)say:(NSString *)str;
相应的实现函数就应该是这样:

int say(id self, SEL _cmd, NSString *str) {
    NSLog(@"%@", str);
    return 100;//随便返回个值
}

class_addMethod这句就应该这么写:

class_addMethod([EmptyClass class], @selector(say:), (IMP)say, "[email protected]:@");

其中types参数为"[email protected]:@“,按顺序分别表示:

i:返回值类型int,若是v则表示void

@:参数id(self)

::SEL(_cmd)

@:id(str)

这些表示方法都是定义好的(Type Encodings),关于Type Encodings的其他类型定义请参考官方文档

最后调用say:方法:

int a = [instance say:@"something"];
NSLog(@"%d", a);

输出something和100。

关于本文所涉及内容的详细信息请参考Objective-C Runtime Reference

本文参考了:

推荐去看看
—以上—

[iOS]如何避免图像解压缩的时间开销

这是一篇译文,(原文"Avoiding Image Decompression Sickness"在此),原文是我看过的非常不错的一篇关于iOS图片显示的一些文章,解决了我的一些疑惑和问题,因此翻译过来分享,为保证一定的通顺性其中一部分内容与原文有些许出入,但我尽量保证了意思的一致性,欢迎指正批评,横线之间为译文,略挫,见谅:


当开始iCatalog.framework的工作时,我发现使用大尺寸图片会引起一些恼人的问题,“大”意味着这个图片有足够大的分辨率(1024×768)来覆盖iPad的整个屏幕,或者覆盖未来Retina Display iPad(如果有的话)的双倍分辨率(2048×1536)屏幕。

想像一个杂志类型的App,一个分页的UIScrollView,每页显示一个UIImageView,一旦某一页进入屏幕区域你就要为这个页创建或者重用一个UIImageView并把它放到scrollView的当前显示区域,即使这个页只有一个像素进入到屏幕区域,你还是要做这些工作。这在模拟器上运行得非常好,但在真机上进行测试,你会发现每次进入下一页时都会有一个明显的延迟。这个延迟来自于将图片从文件解压缩并渲染到屏幕上这一系列的工作。不幸的是UIImage仅在图片将要显示的时候做这个解压工作。

因为添加一个view到当前的view层次结构中必须在主线程上进行,所以图片的解压缩和之后渲染到屏幕上的工作也在主线程进行,这就是这个延迟产生的原因,这个问题也可以在store里的其他有类似这种效果的app中发现。

一般我们使用的图片有两种主要格式,jpeg和png。Apple通常推荐你使用png作为用户界面的图片格式,这些图片会被一个叫pngcrush开源的工具优化(译者注:这个工具就在/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/pngcrush ),这样对于iOS设备就可以在显示时更快地进行解压和渲染。iPad平台上首批出现的杂志应用,比如Wired,就曾用过png作为杂志内容图片的格式,这导致了这个应用的某一版本大小超过了500MB(link)[http://www.cocoanetics.com/2010/05/saturday-morning-breakfast-wired-emag/]

虽然png格式的图片会被事先优化好,但是这并不意味着在所有情况下png都是最佳的图片格式,png对于那些app中自带的图片来说非常好,但是对于要从internet上down下来的图片来说又会怎样呢。png和jpeg这两种格式都有各自的优缺点:

png格式的图片有alpha通道,jpeg则没有。png无损压缩,jpeg允许你选择0-100%的压缩质量。如果需要alpha通道(透明),就只能用png格式。但是如果你不需要一个完美的图片,就可以使用jpeg格式,jpeg格式会忽略那些你看不到的信息,对于大部分的图片可以使用60-70%的压缩质量而不对图片造成明显的影响,对于比如文字那样有"sharp pixels"的图片就可能需要较高的压缩质量,对于照片可以使用较低的压缩质量。

来看一下一个图片的空间消耗:

  1. 磁盘空间或者通过internet传输所消耗的空间
  2. 解压缩空间,通常是长X宽X高X4字节(RGBA)
  3. 当显示在一个view中时,view本身也需要空间来存储layer

对于这里的第一个问题,有一个可能的优化方法:将压缩的文件拷贝到内存中不如映射到内存中,NSData有能力来假设一块磁盘空间是在内存中的,这样当访问这个图片时实际上就是从磁盘访问而不是从内存。据说CGImage知道哪种访问方式是最高效的,UIImage只是将CGImage封装了一下。

对于“将这些像素显示到屏幕上最快要多久?”这个问题,显示一个图片所消耗的时间由以下三个因素决定:

  1. 从磁盘上alloc/init UIImage的时间
  2. 解压缩的时间
  3. 将解压缩后的比特转换成CGContext的时间,通常需要改变尺寸,混合,抗锯齿工作。

要逐一解答各个问题,我们需要一个benchmark来测量。

测试环境和测试内容

继续阅读[iOS]如何避免图像解压缩的时间开销

编译你自己的MobileTerminal

先扯点题外话,没兴趣看的直接跳过这一段:话说iOS 5.0.1完美越狱终于出来了,虽然还有一些Bug(比如ibooks),以及一些4.x时代的越狱软件不能用,但是终归是出来了,最近还有weiphone的好心人分享4s的siri认证,就是那个Spire一直下不下来很蛋疼。再吐槽下Sbsettings,虽然放到通知栏里了,但是也太影响加载速度了吧,你就不能在viewdidappear里面加载那几个图标么(也许通知栏的控件没有这个方法,但是那个天气股票啥的都挺流畅的啊),搞得通知栏没有一回是流畅拉下来的。依赖的Activator显然已经没什么用了,就应该老实儿做个通知栏版的Sbsettings,也不能费多少劲。

吐完槽进入正题:MobileTerminal是一个写的很蛋疼的app,为什么很蛋疼,原因有很多:

  • 删除(backspace/delete)操作总是有历史字母残留,这个不知道为什么,对终端的实现不是很了解
  • 左下角那个快捷菜单不能添加ESC这种常用的快捷键
  • swipe left right up down 的手势识别率太低,就不应该用这种不好识别的手势,本来终端就是个没什么触摸交互的东西,手势操作看不到结果。
  • 等等…

这里先说下环境:Xcode 4.2,iOS SDK 5.0, 有开发者帐号证书

幸好编译MobileTerminal还算简单,编译脚本该有的都有了,不用去操心这些实在是很方便,大概步骤如下:

  • 找个目录 svn checkout http://mobileterminal.googlecode.com/svn/ mobileterminal-read-only 这个目录路径最好全英文,无空格,否则编译deb时有问题
  • check下来的东西有好几个project,真正有用的在branches/applesdk/MobileTerminal 打开这个project
  • Target选择成MobileTerminal,编译到真机
  • 编译遇到错误 Command ./build_svnversion.sh failed with exit code 1 问题,这个svnversion似乎是用来生成版本号的,我们也不需要就可以无视。打开项目配置文件,选择Targets下面的MobileTerminal,BuildPhases >> Target Dependencies里面删除svnversion(MobileTerminal)
  • 继续编译,多了一个错误:TerminalGroupView.m 文件里#import部分,找不到 Perferences/Settings.h;直接改成#import "Settings.h"
  • 继续编译,可能有签名问题,对于有开发者帐号的就直接设置好签名就OK了,没有帐号的如果之前已经做好XCode免证书调试的各种工作了这个错误应该不会出现,具体没有条件尝试,大家自行解决吧,不是大问题。
  • 继续编译,第一次遇到的错误没有了,现在在 MobileTerminalAppDelegate.m 文件里提示找不到 svnversion.h;删除这句import,修改applicationDidFinishLaunching:里面的SVN_VEFRSION为任意数字,比如999
  • 过程中还可能遇到找不到gen_entitlements.py的问题,这个估计是XCode3.x版本免证书调试遗留下来的东西(参考这里),解决方法,终端中输入如下命令(要sudo):

    mkdir /Developer/iphoneentitlements312
    cd /Developer/iphoneentitlements312
    curl -O http://www.alexwhittemore.com/iphone/gen_entitlements.txt
    mv gen_entitlements.txt gen_entitlements.py
    chmod 777 gen_entitlements.py

经过以上修改,编译就应该成功,在你的机器上就应该会出现沙盒版的MobileTerminal,运行会提示在沙盒里不能fork,这就需要将App安装到/Application/下,直接将编译好的terminal.app拖过去运行会秒退,需要编译deb包,像Cydia那样安装。

Target选择deb,编译,可能会提示缺少dpkg-deb;直接下载这个二进制文件dpkg-deb-fat(参考这里),放到/usr/local/bin/下面(或者/usr/bin/),重命名为dpkg-deb,在终端直接敲dpkg-deb命令检查以下,接着编译成功,编译好的deb在~/Library/Developer/Xcode/DerivedData/MobileTerminal-xxxxxxxxxx/Build/Products/Debug-iphoneos/ 下面,这个路径可以通过在项目Products文件夹右键点击已经编译好的Terminal.app >> Show in Finder来找到

至于Deb包的安装我就不用多说了,iFile傻瓜式还是命令行dpkg,再或者蛋疼地架个repo,方法很多了。

至于Terminal的修改我还没有研究,最近也比较忙没那闲工夫折腾,有兴趣的自己看看吧,牛人可以挑几个bug啥的上传到code上以后也可以作为炫耀的资本(开完笑),以后Cydia上的那个版本就可能时你编译的了。

PS.其实MobleTerminal可以直接在模拟器上运行,没有沙盒问题,证书问题,也方便调试

最后感谢一下为MobileTerminal作出贡献的我不认识的大牛们,虽然我之前吐了很多槽,幸好你们看不懂中文。

—以上—