1.为何block在ARC下会内存泄漏,MRC却没事?
2.为何加上 __block 之后,block就可以修改外部变量的值了?
3.block属性为什么要使用copy?
4.为什么在block的内部不能修改外部的变量?
===================================================
1.为何block在ARC下会内存泄漏,MRC却没事?Arc和MRC下block的区别。
int (^plus1)(int a, int b)=^int(int a, int b){
return a+b;
};
NSLog(@"plus1 = %@",plus1);
int c = 100;
int(^plus2)(int a, int b) = ^int(int a, int b){
return c+a+b;
};
NSLog(@"plus2 = %@",plus2);
arc下输出是:
plus1 = <__NSGlobalBlock__: 0x10a5ac350>
plus2 = <__NSMallocBlock__: 0x7fdecbf41270>
mrc下输出是:
plus1 = <__NSGlobalBlock__: 0x10f55b350>
plus2 = <__NSStackBlock__: 0x7fff50bdebe0>
那是不是arc下面不会出现NSStackBlock呢,测试下面一段代码:
1.
__weak int(^plus2_5)(int a, int b) = ^int(int a, int b){
return c+a+b;
};
NSLog(@"plus2_5 = %@",plus2_5);
2.
__weak int(^plus3)(int a, int b) = plus2;
NSLog(@"plus3 = %@",plus3);
3.
NSLog(@"plus4 = %@",^int(){
int a = c;
return a;
});
输出为:
plus2_5 = <__NSStackBlock__: 0x7fff5bcfcbb8>
plus3 = <__NSMallocBlock__: 0x7f7f7b625110>
plus4 = <__NSStackBlock__: 0x7fff5bcfcb78>
可以看出单独对block的声明,block还是会分布在栈上。而plus3为什么分布在了堆上,这是因为plus3的声明类似于[plus2 copy],自然要将其拷贝到堆上。
2.为何加上 __block 之后,block就可以修改外部变量的值了?
未加__block前,如果block里调用了外部变量,block会copy一个对象,相当于一个对象的副本。所以修改副本的值,并不会修改原对象的值。而加了__block之后,block内部实现会增加一个结构体,结构体里包含了外部变量的指针,有了指针就能随意修改原来对象的值了。
- 参考:
- http://blog.csdn.net/wildfireli/article/details/22063001#0-tsina-1-77995-397232819ff9a47a7b7e80a40613cfe1
- http://blog.csdn.net/abc649395594/article/details/47086751
3.block属性为什么要使用copy?
当代码块函数体发生变化的时候,例如访问或者修改外部变量
- 如果是ARC(自动)在堆区 NSMallocBlock
- 如果是MRC(手动)在栈区 NSStackBlock
int num = 10;
void(^block)() = ^{
NSLog(@"%d",num);
};
NSLog(@"%d",block);
//定义里一个block属性为task
int num = 10;
void(^block)() = ^{
NSLog(@"%d",num);
};
self.task = block;
NSLog(@"%@--%@",block,self.task);//栈区,堆区
- MRC环境下,在定义block为属性时, 使用copy的原因, 是把block从栈区拷贝到堆区,因为栈区中的变量出了作用域之后就会被销毁,无法在全局使用, 所以应该把栈区的属性拷贝到堆区中全局共享,这样就不会被销毁了, 在MRC手动管理的就是堆区, 不需要系统管理, MRC环境必须使用copy把变量拷贝到全局的堆区
- 如果是ARC的环境下, 就可以不使用copy修饰, 因为ARC下的属性本来就在堆区
- 很早的时候MRC的block属性都是在栈区的, copy之后就到堆区了
- 当前的ARC的block属性默认都在堆区, 使用copy知识沿袭了历史的习惯, 使用strong也是没有问题的
- 在MRC下必须使用self.task = block; 给属性赋值,在赋值的时候会调用setter方法,会把栈区的block拷贝到堆区, 如果使用_task的方式赋值不会去copy, 所以在MRC下属性都用copy修饰
- 在ARC下可以使用_task, 因为arc下默认属性就是在堆区
4.为什么在block的内部不能修改外部的变量?
作用域不一样,就跟俩函数传值一样。
-
Block 能否添加到数组里?
可以,但是必须是已经copy到堆上之后才行,否则,如果释放了就会崩溃了。
5.进程间如何通信?
XPC、剪切板、URL Schemes、App Group。
URL Schema: 算是实现了某种程度的进程间通信,但这种方式的一个缺点是,同一时刻还是只能有一个进程在前台,主动呼叫的应用在调用成功后必须进入后台,所以能传递的只有URL中所带的参数或annotation中所带的参数。调用的过程中会出现应用之间的切换,用户体验不好。
系统服务一般没有沙盒限制,如果能截取系统服务的xpc信息,就能获取沙盒外的权限。ios8出现过一个xpc的漏洞。
6.线程和进程的区别是什么?单CPU运行多进程的原理是什么?
- 进程有独立的地址空间,一个进程崩溃后,不会影响其它进程,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健 壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
- 进程至少有一个线程,也可能并发多个线程。
- 在操作系统的管理下,所有正在运行的进程轮流使用CPU,每个进程允许占用CPU的时间非常短(比如10毫秒),这样用户根本感觉不出来 CPU是在轮流为多个进程服务,就好象所有的进程都在不间断地运行一样。但实际上在任何一个时间内有且仅有一个进程占有CPU。 如果一台计算机有多个CPU,情况就不同了,如果进程数小于CPU数,则不同的进程可以分配给不同的CPU来运行,这样,多个进程就是真正同时运行的,这便是并行。但如果进程数大于CPU数,则仍然需要使用并发技术。 进行CPU分配是以线程为单位的,一个进程可能由多个线程组成,这时情况更加复杂,但简单地说,有如下关系:
总线程数<= CPU数量:并行运行
总线程数> CPU数量:并发运行
http://blog.sina.com.cn/s/blog_134451adb0102wfyp.html
7.多线程的原理是什么?
同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)
多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)
如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象
思考:如果线程非常非常多,会发生什么情况?
CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源
每条线程被调度执行的频次会降低(线程的执行效率降低)
不过有了多核CPU,可以实现真正意义上的多线程并发执行。
与超线程CPU在逻辑上模拟双核不同,多核CPU每个核心都可以独立执行一个线程,是真正意义的多个物理CPU。
如果你的程序的线程数少于CPU的核心数,且系统此时没有其他进程同时运行,那么这个程序的每个线程会享有一个CPU,当同时运行的线程数多于CPU核心数时,CPU会采用一定的调度算法每隔一段时间就将这些线程调入或调出CPU,以确保每个线程都能分享一部分CPU时间,实现多线程并发。
8.Category为何不能添加成员变量?
9.若定义了一个类MyView继承于UIView,在MyView里增加了一个aaa的属性,系统是怎么保证如果系统更新了UIView里新增了一个bbb的属性跟MyView里的aaa内存不重叠的?
10.内联函数和宏的差别是什么?
http://m.blog.csdn.net/pengjin1985/article/details/7665470
11.简述Https原理。
https://www.jianshu.com/p/44ed0f471284
12.NSTimer、CADisplayLink 和 GCD定时器的区别?
NSTimer、CADisplayLink必须在runloop里执行才行,如果在非子线程,必须让runloop运行起来才会执行。而GCD不用。
nstimer会将所持有的对象retain。
CADisplayLink跟屏幕刷新频率有关,适合做动画重绘相关时用。
GCD比nstimer要准一些,nstimer延时严重些,还会受runloop模式的影响。
13.automic是线程安全的吗?
不是。当使用atomic时,虽然对属性的读和写是原子性的,但是仍然可能出现线程错误:当线程A进行写操作,这时其他线程的读或者写操作会因为该操作而等待。当A线程的写操作结束后,B线程进行写操作,然后当A线程需要读操作时,却获得了在B线程中的值,这就破坏了线程安全,如果有线程C在A线程读操作前release了该属性,那么还会导致程序崩溃。所以仅仅使用atomic并不会使得线程安全,我们还要为线程添加lock来确保线程的安全。
14.HTTP请求的结构。
- 请求(Request)的结构:
- Request Line(请求行): 包括Method,是get还是post,请求的资源(URI),协议版本等。
- Request Header(消息报头): 其他参数,如接受的编码类型、接收的图片类型、语言等。
- Request Body(请求正文):
- 响应(Response)的结构:
- Response Line(响应状态行):包括版本号、状态码、message。
- Response Header (响应报头):
- Response Body (响应正文) :
15.load和initialize的异同
不同点:
- load是程序运行起来前调用的,肯定会在main函数之前完成。initialize是懒加载,第一次调用该类的地方调用。
- 若子类未实现 initialize,第一次加载子类时也会执行该方法(执行父类里的方法,且父类里的 initialize 会被执行两次)。而若子类未实现load方法,不会执行 load 方法。
- 若category也重写了load方法,不会覆盖对应类的方法。对应类的load先调用,再调用category的load方法,执行顺序: 父类->子类->分类。
- load 里调用其他类是不安全的,因为无法判断其他类是否已经执行了load 方法。只有load完成后,类才能正常使用。
相同点:
- 都是父类先调用,子类后调用。
- 都是线程安全的,一个线程访问时,另一个线程无法访问。所以俩方法都要精简,否则会阻塞。
http://www.cocoachina.com/ios/20161012/17732.html
16.uibutton的继承关系?UIview和CALayer的关系,苹果为何要这么设计,为何不直接合成一个UILayer?。
uibutton->uicontrol->uiview->uirespond
uicontrol: 具有addTarget这些方法。
uiview: 具有drawRect、layoutSubview这些方法。
uirespond:具有touchBegan、touchMove、touchEnd这些方法。
UIview继承于uirespond,所以可以响应各种触摸事件。而calayer继承于 nsobject,是Quartz Core中的,用于处理显示层面的东西,包括动画效果。UIview因为有了calayer才有了显示功能,通过calayer,可以修改view的圆角、阴影、边框等。
各司其职,避免所有代码都堆在一个类里,更容易管理维护。
17.动态库和静态库的区别和优缺点,及苹果为何不允许动态库。
- 静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要该静态库.
- 动态库在程序编译期间不会被链接到目标代码中,只是在程序运行时才被载入,在程序运行期间还需要动态库的存在.
优缺点: - 动态库体积小,可以多个进程共享同一个库。
- 动态库可以不重新编译,就能动态的更新库文件内容。
- 都可以实现模块化,分工合作。
苹果并不支持动态库,但系统的库是动态库。为啥不支持动态库,一是因为iOS是单进程的,不需要共享库文件,二是AppStore不支持部分更新App,只能整个升级。
18.述说iOS的事件响应链。
事件传递:UIApplication
-> UIWindow
->UIController
->UIView
->子View
事件响应:子view
->父view
->UIController
->UIWindow
->UIApplication
.
- 在事件的响应中,如果某个控件实现了
touches...
方法,则这个事件将由该控件来接受,如果调用了[super touches….];
就会将事件顺着响应者链条往上传递,传递给上一个响应者;接着就会调用上一个响应者的touches….
方法。 - 若写了
[super touches...]
,就可以实现一个事件多个控件处理;若不写,就只有当前的控件处理。 - hitTest 和 pointInside。
https://www.jianshu.com/p/2e074db792ba
19.weak修饰的属性在被清空时是如何将属性值置为nil的?
系统会将所有weak属性存在一个hash表中,将weak属性所指的对象的内存地址作为key,当weak所指向的对象被清空时,系统会通过清空对象的内存地址key,从hash表中获取weak属性,将其赋值为nil。
20.UITableView的优化防卡顿。
- 非UI的操作尽量放到子线程。
- cell里的控件尽量少用半透明的。
- 图片圆角,可以让设计师直接提供圆角图片,或者用代码把图片剪成圆角再加载。
- 图片要用缓存,比如SDWebImage;
- 网络加载下来的图片
size
跟显示的frame
尺寸匹配,避免控件去压缩图片。 - cell里最好别用xib或者sb,减少不必要的操作。
- cell的高度最好提前算好了,到时候直接加载,如果边滚动边计算效率会很低。
- 对于有相似控件的cell,尽量用同一个控件,不要重新创建。
- 文本高度的计算可以放到后台执行。
- 图像的绘制通常是指用那些以 CG 开头的方法把图像绘制到画布中,然后从画布创建图片并显示这样一个过程。这个最常见的地方就是 [UIView drawRect:] 里面了。由于 CoreGraphic 方法通常都是线程安全的,所以图像的绘制可以很容易的放到后台线程进行。一个简单异步绘制的过程大致如下(实际情况会比这个复杂得多,但原理基本一致):
- (void)display {
dispatch_async(backgroundQueue, ^{
CGContextRef ctx = CGBitmapContextCreate(...);
// draw in context...
CGImageRef img = CGBitmapContextCreateImage(ctx);
CFRelease(ctx);
dispatch_async(mainQueue, ^{
layer.contents = img;
});
});
}
- 异步绘制时,若tableView迅速的滑动,中间滑过去的好多cell要及时取消绘制。
21. GCD、NSOperationQueue、NSThread的优缺点比较。
尽管GCD很方便,也很高效,但是有时候并不是最佳方案。以下是NSOperationQueue比GCD的优点:
- 可以方便的取消某个操作。可以方便的调用cancel方法,不过已经启动的任务无法取消了。而GCD想要实现取消功能,只能开发者自己实现。(iOS8以后也可以通过dispatch_block_cancel进行取消)
- 方便的制定依赖关系。
[operationB addDependency:operationA];// 操作B依赖于操作A
- GCD中
dispatch_barrier_async
也算是优先级。
- 可以通过KVO检测状态,如
isCanceled
、isFinished
。 - 可以方便的设置优先级。默认所有operation都拥有“普通”优先级,不过可以通过setQueuePriority:方法来提升或降低operation对象的优先级。优先级只能应用于相同queue中的operations。如果应用有多个operation queue,每个queue的优先级等级是互相独立的。因此不同queue中的低优先级操作仍然可能比高优先级操作更早执行。
注意:优先级不能替代依赖关系,优先级只是对已经准备好的 operations确定执行顺序。先满足依赖关系,然后再根据优先级从所有准备好的操作中选择优先级最高的那个执行。
GCD也能设置优先级,不过是队列的优先级,对于同一个队列里的任务不能设置优先级。
Global://有四个优先级
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)//第一个参数为优先级,这里为高优先级,第二个目前未使用,并且应该始终为0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)//默认优先级
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)//低优先级
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)//后台优先级
- 设置最大并发数:
setMaxConcurrentOperationCount:
GCD也可以通过信号量实现最大并发数的修改。
- 如果异步操作的过程需要更多的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。底层代码中,任务之间不太互相依赖,而需要更高的并发能力,GCD则更有优势。
22.深入理解runtime
https://www.cnblogs.com/ioshe/p/5489086.html
23. 以下两行代码分别返回的是啥,二者的关系是啥?
id A = [Student class];
id B = [Student alloc];
B没有疑问,就是一个Student类的实例。那A呢?
A的类型是Class
,其定义如下:
typedef struct objc_class *Class;
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
类其实是元类的一个对象,元类的方法列表都是类方法。所以A返回的就是Student类元类的一个类对象。[Student alloc]
实际上是发送了一个消息给他的类对象。
24.Runtime解释[receiver message]
的全过程。
- 首先检测这个 selector 是不是要忽略。比如 Mac OS X 开发,有了垃圾回收就不理会 retain,release 这些函数。
- 检测这个 selector 的 target 是不是 nil,Objc 允许我们对一个 nil 对象执行任何方法不会 Crash,因为运行时会被忽略掉。
- 编译后,
[receiver message]
会被转成以下代码:
objc_msgSend(receiver, selector)
- 通过
isa
指针,找到receiver
所属的类,开始查找这个类的实现IMP
,先从cache
里查找,如果找到了就运行对应的函数去执行相应的代码。 - 如果 cache 找不到,就找类的方法列表中是否有对应的方法。
- 如果类的方法列表中找不到,就通过
super_class
到父类的方法列表中查找,一直找到 NSObject 类为止。 - 如果还找不到,就要开始进入动态方法解析和消息转发(三个方法)了。
- 若没有找到相应的方法接盘,就把异常抛出,打印log。
25. GCC、LLVM、Clang的关系
在XCode中,我们经常会看到这些编译选项(如下图),有些人可能会有些茫然,本文将对GCC4.2、LLVM GCC 4.2、LLVM compliler 2.0三个编译选项进行一个详细的介绍。
GCC
GCC(GNU Compiler Collection,GNU编译器套装),是一套由 GNU 开发的编程语言编译器。它是一套以 GPL 及 LGPL 许可证所发行的自由软件,也是 GNU计划的关键部分,亦是自由的类Unix及苹果电脑 Mac OS X 操作系统的标准编译器。
GCC 原名为 GNU C 语言编译器,因为它原本只能处理 C语言。GCC 很快地扩展,变得可处理 C++。之后也变得可处理 Fortran、Pascal、Objective-C、Java, 以及 Ada与其他语言。
LLVM
LLVM 是 Low Level Virtual Machine 的简称,这个库提供了与编译器相关的支持,能够进行程序语言的编译期优化、链接优化、在线编译优化、代码生成。简而言之,可以作为多种语言编译器的后台来使用。如果这样还比较抽象的话,介绍下 Clang 就知道了:Clang 是一个 C++ 编写、基于 LLVM、发布于 LLVM BSD 许可证下的 C/C++/Objective C/Objective C++ 编译器,其目标(之一)就是超越 GCC。
LLVM历史
Apple(包括中后期的NeXT) 一直使用GCC作为官方的编译器。GCC作为开源世界的编译器标准一直做得不错,但Apple对编译工具会提出更高的要求。
一方面,是Apple对Objective-C语言(甚至后来对C语言)新增很多特性,但GCC开发者并不买Apple的帐——不给实现,因此索性后来两者分成两条分支分别开发,这也造成Apple的编译器版本远落后于GCC的官方版本。另一方面,GCC的代码耦合度太高,不好独立,而且越是后期的版本,代码质量越差,但Apple想做的很多功能(比如更好的IDE支持)需要模块化的方式来调用GCC,但GCC一直不给做。甚至最近,《GCC运行环境豁免条款 (英文版)》从根本上限制了LLVM-GCC的开发。 所以,这种不和让Apple一直在寻找一个高效的、模块化的、协议更放松的开源替代品,于是Apple请来了编译器高材生Chris Lattner(2000年,本科毕业的Chris Lattner像中国多数大学生一样,按部就班地考了GRE,最终前往UIUC(伊利诺伊大学厄巴纳香槟分校),开始了艰苦读计算机硕士和博士的生涯。在这阶段,他不仅周游美国各大景点,更是努力学习科学文化知识,翻烂了“龙书”(《Compilers: Principles, Techniques, and Tools》),成了GPA牛人【注:最终学分积4.0满分】,以及不断地研究探索关于编译器的未知领域,发表了一篇又一篇的论文,是中国传统观念里的“三好学生”。他的硕士毕业论文提出了一套完整的在编译时、链接时、运行时甚至是在闲置时优化程序的编译思想,直接奠定了LLVM的基础。LLVM在他念博士时更加成熟,使用GCC作为前端来对用户程序进行语义分析产生IF(Intermidiate Format),然后LLVM使用分析结果完成代码优化和生成。这项研究让他在2005年毕业时,成为小有名气的编译器专家,他也因此早早地被Apple相中,成为其编译器项目的骨干)。
刚进入Apple,Chris Lattner就大展身手:首先在OpenGL小组做代码优化,把LLVM运行时的编译架在OpenGL栈上,这样OpenGL栈能够产出更高效率的图形代码。如果显卡足够高级,这些代码会直接扔入GPU执行。但对于一些不支持全部OpenGL特性的显卡(比如当时的Intel GMA卡),LLVM则能够把这些指令优化成高效的CPU指令,使程序依然能够正常运行。这个强大的OpenGL实现被用在了后来发布的Mac OS X 10.5上。同时,LLVM的链接优化被直接加入到Apple的代码链接器上,而LLVM-GCC也被同步到使用GCC4代码。
Clang历史
- Apple吸收Chris Lattner的目的要比改进GCC代码优化宏大得多——GCC系统庞大而笨重,而Apple大量使用的Objective-C在GCC中优先级很低。此外GCC作为一个纯粹的编译系统,与IDE配合得很差。加之许可证方面的要求,Apple无法使用LLVM 继续改进GCC的代码质量。于是,Apple决定从零开始写 C、C++、Objective-C语言的前端 Clang,完全替代掉GCC。
- 正像名字所写的那样,Clang只支持C,C++和Objective-C三种C家族语言。2007年开始开发,C编译器最早完成,而由于Objective-C相对简单,只是C语言的一个简单扩展,很多情况下甚至可以等价地改写为C语言对Objective-C运行库的函数调用,因此在2009年时,已经完全可以用于生产环境。C++的支持也热火朝天地进行着。
- 下面这张图将显示GCC、LLVM-GCC、LLVM Compiler这三个编译选项的不同点:
对比
作为一种新的编译器,我们来看Clang和GCC各有什么优缺点: - Clang特性
快:通过编译 OS X 上几乎包含了所有 C 头文件的 carbon.h 的测试,包括预处理 (Preprocess),语法 (lex),解析 (parse),语义分析 (Semantic Analysis),抽象语法树生成 (Abstract Syntax Tree) 的时间,Clang 是 Apple GCC 4.0 的 2.5x 快。(2007-7-25)
内存占用小:Clang 内存占用是源码的 130%,Apple GCC 则超过 10x。
诊断信息可读性强:我不会排版,推荐去网站观看。其中错误的语法不但有源码提示,还会在错误的调用和相关上下文的下方有~~~~~和^的提示,相比之下 GCC 的提示很天书。
GCC 兼容性。
设计清晰简单,容易理解,易于扩展增强。与代码基础古老的 GCC 相比,学习曲线平缓。
基于库的模块化设计,易于 IDE 集成及其他用途的重用。由于历史原因,GCC 是一个单一的可执行程序编译器,其内部完成了从预处理到最后代码生成的全部过程,中间诸多信息都无法被其他程序重用。Clang 将编译过程分成彼此分离的几个阶段,AST 信息可序列化。通过库的支持,程序能够获取到 AST 级别的信息,将大大增强对于代码的操控能力。对于 IDE 而言,代码补全、重构是重要的功能,然而如果没有底层的支持,只使用 tags 分析或是正则表达式匹配是很难达成的。
当然,GCC 也有其优势:
- 支持 JAVA/ADA/FORTRAN
- 当前的 Clang 的 C++ 支持落后于 GCC,参见http://clang.llvm.org/cxx_status.html。(近日 Clang 已经可以自编译,见http://www.phoronix.com/scan.php?page=news_item&px=Nzk2Mw)
- GCC 支持更多平台
- GCC 更流行,广泛使用,支持完备
- GCC 基于 C,不需要 C++ 编译器即可编译
要选择哪个
那么三个编译选项,要选择哪一个呢?目前不推荐使用老的GCC4.2,因为苹果不会维持它了,而且LLVM-GCC看起来会更好。在项目中途改编译选项可是一个大变动,所以,如果你要改,当然需要经过慎重完整的测试。
对新的项目而言,LLVM-GCC看起來应该是个安全的选择,苹果公司认为它够稳定够成熟,所以才把它当做Xcode 4的预设选项(你或许不会把稳定成熟这两个字眼跟Xcode 4本身画上等号),而且,既然选项使用的是GCC parser,向后兼容性应该没问题。
我说LLVM-GCC是个安全的选项,但我并不是指Clang/LLVM比较不安全,只是成熟度还沒那么高效了,我将一些以前的代码拿到Xcode 4上,使用LLVM 2.0编译器重新编译,到目前为止还沒发现任何问题。
参考文档:
http://baike.baidu.com/view/4848.htm
http://hi.baidu.com/zhanghuikl/blog/item/71e8a6018172df0f728da53e.html
http://www.programmer.com.cn/9436/