很多引用的类库暂时还不支持.麻烦的是对大多数第三方库需要加禁用arc的编译flag
(
如果你的项目使用的是 ARC 模式,则为非 ARC 模式的代码文件加入 -fno-objc-arc 标签。
添加标签的方法:
- 打开:你的target -> Build Phases -> Compile Sources.
- 双击对应的 *.m 文件
- 在弹出窗口中输入上面提到的标签 -fobjc-arc / -fno-objc-arc
- 点击 done 保存
)
虽然objective-c 2.0支持垃圾收集器(Garbage Collection,简称GC),但是垃圾收集器只能在MAC程序上开启,ios上没办法用。就算在MAC应用程序上可以用,GC也会有性能上的损耗。
现在LLVM3.0多了一个给力的新东西,叫Automatic Reference Counting。
ARC是Objective-C编译器的特性,而不是运行时特性或者垃圾回收机制,ARC所做的只不过是在代码编译时为你自动在合适的位置插入release或autorelease,就如同之前MRC时你所做的那样。
168 | 这个小工具是Edit->Refactor下的Convert to Objective-C ARC |
SURL *fileURL = [[NSBundle mainBundle] URLForResource:filename withExtension:nil]; |
184 | if (fileURL != nil) { |
185 | SystemSoundID theSoundID; |
186 | OSStatus error = AudioServicesCreateSystemSoundID((CFURLRef)fileURL, &theSoundID); |
187 | if (error == kAudioServicesNoError) { |
188 | soundID = theSoundID; |
192 | 这里代码尝试把一个NSURL指针强制转换为一个CFURLRef指针。这里涉及到一些Core Services特别是Core Foundation(CF)的东西,AudioServicesCreateSystemSoundID()函数接受CFURLRef为参数,这是一个CF的概念,但是我们在较高的抽象层级上所建立的是NSURL对象。在Cocoa框架中,有很多顶层对象对底层的抽象,而在使用中我们往往可以不加区别地对这两种对象进行同样的对待,这类对象即为可以”自由桥接”的对象(toll- free bridged)。NSURL和CFURLRef就是一对好基友好例子,在这里其实CFURLRef和NSURL是可以进行替换的。 |
194 | 通常来说为了代码在底层级上的正确,在iOS开发中对基于C的API的调用所传入的参数一般都是CF对象,而Objective-C的API调用都是传入NSObject对象。因此在采用自由桥接来调用C API的时候就需要进行转换。但是在使用ARC编译的时候,因为内存管理的原因,编译器需要知道对这些桥接对象要实行什么样的操作。如果一个NSURL对象替代了CFURLRef,那么在作用区域外,应该由谁来决定内存释放和对象销毁呢?为了解决这个问题,引入了bridge,bridge_transfer和__bridge_retained三个关键字。关于选取哪个关键字做转换,需要由实际的代码行为来决定。如果对于自由桥接机制感兴趣,大家可以自己找找的相关内容,比如适用类型、内部机制和一个简介~之后我也会对这个问题做进一步说明 |
196 | 回到demo,我们现在在上面的代码中(CFURLRef)前加上__bridge进行转换。 |
为了方便查找,再此列出一些在转换时可能出现的问题,当然在我们使用ARC时也需要注意避免代码中出现这些问题: |
212 | “Cast … requires a bridged cast” |
215 | Receiver type ‘X’ for instance message is a forward declaration |
216 | 这往往是引用的问题。ARC要求完整的前向引用,也就是说在MRC时代可能只需要在.h中申明@ class 就可以,但是在ARC中如果调用某个子类中未覆盖的父类中的方法的话,必须对父类.h引用,否则无法编译。 |
218 | Switch case is in protected scope |
219 | 现在 switch 语句必须加上{}了,ARC需要知道局部变量的作用域,加上{}后 switch 语法更加严格,否则遇到没有 break 的分支的话内存管理会出现问题。 |
221 | A name is referenced outside the NSAutoreleasePool scope that it was declared in… |
222 | 这是由于写了自己的autoreleasepool,而在转换时在原来的pool中申明的变量在新的@autoreleasepool中作用域将被局限。解决方法是把变量申明拿到pool的申请之前。 |
224 | ARC forbids Objective-C objects in structs or unions |
225 | 可以说ARC所引入的最严格的限制是不能在C结构体中放OC对象了..因此类似下面这样的代码是不可用的 |
233 | UIImage *selectedImage; |
234 | UIImage *disabledImage; |
237 | 这个问题只有乖乖想办法了..改变原来的结构什么的.. |
另外,在MRC时代一个常做的事情是在dealloc里把指向自己的delegate设成nil(否则就等着EXC_BAD_ACCESS吧 :P),而现在一般delegate都是weak的,因此在self被销毁后这个指针自动被置成nil了,你不用再为之担心,好棒啊..
通过加载xib得到的用户界面,在其从xib文件加载时,就已经是view hierarchy的一部分了,而view hierarchy中的指向都是strong的。因此outlet所指向的UI对象不应当再被hold一次了。将这些outlet写为weak的最显而易见的好处是你就不用再viewDidUnload方法中再将这些outlet设为nil了(否则就算view被摧毁了,但是由于这些UI对象还在被outlet指针指向而无法释放,代码简洁了很多啊..)。
350 | MainViewController现在剩下的问题都是桥接转换问题了~有关桥接的部分有三处: |
352 | (NSString *)CFURLCreateStringByAddingPercentEscapes(…):CFStringRef至NSString * |
353 | (CFStringRef)text:NSString *至CFStringRef |
354 | (CFStringRef)@“!‘();:@&=+$,/?%#[]”:NSString 至CFStringRef |
355 | 编译器对前两个进行了报错,最后一个是常量转换不涉及内存管理。 |
357 | 关于toll- free bridged,如果不进行细究,NSString和CFStringRef是一样的东西,新建一个CFStringRef可以这么做: |
361 | CFStringRef s1 = [[NSString alloc] initWithFormat:@ "Hello, %@!" ,name]; |
363 | 然后,这里alloc了而s1是一个CF指针,要释放的话,需要这样: |
369 | 相似地可以用CFStringRef来转成一个NSString对象(MRC): |
377 | CFStringRef s2 = CFStringCreateWithCString(kCFAllocatorDefault,bytes, kCFStringEncodingMacRoman); |
378 | NSString *s3 = (NSString *)s2; |
383 | 在ARC中,编译器需要知道这些指针应该由谁来负责释放,如果把一个NSObject看做是CF对象的话,那么ARC就不再负责它的释放工作(记住ARC是only for NSObject的)。对于不需要改变持有者的对象,直接用简单的bridge就可以了,比如之前在SoundEffect.m做的转换。在这里对于(CFStringRef)text这个转换,ARC已经负责了text这个NSObject的内存管理,因此这里我们需要一个简单的bridge。而对于CFURLCreateStringByAddingPercentEscapes方法,方法中的create暗示了这个方法将形成一个新的对象,如果我们不需要NSString转换,那么为了避免内存的问题,我们需要使用CFRelease来释放它。而这里我们需要一个NSString,因此我们需要告诉编译器接手它的内存管理工作。这里我们使用bridge_transfer关键字,将内存管理权由CF object移交给NSObject(或者说ARC)。如果这里我们只用bridge的话,内存管理的负责人没有改变,那么这里就会出现一个内存泄露。另外有时候会看到CFBridgingRelease(),这其实就是transfer cast的内联写法..是一样的东西。总之,需要记住的原则是,当在涉及CF层的东西时,如果函数名中有含有Create, Copy, 或者Retain之一,就表示返回的对象的retainCount+1了,对于这样的对象,最安全的做法是将其放在CFBridgingRelease()里,来平衡retain和release。 |
385 | 还有一种bridge方式,__bridge_retained。顾名思义,这种转换将在转换时将retainCount加1。和CFBridgingRelease()相似,也有一个内联方法CFBridgingRetain()来负责和CFRelease()进行平衡。 |
387 | 需要注意的是,并非所有的CF对象都是自由桥接的,比如Core Graphics中的所有对象都不是自由桥接的(如CGImage和UIImage,CGColor和UIColor)。另外也不是只有自由桥接对象才能用bridge来桥接,一个很好的特例是 void (指向任意对象的指针,类似id),对于 void 和任意对象的转换,一般使用_bridge。(这在将ARC运用在Cocos2D中很有用) (http://www.oschina.net/code/snippet_196012_24966) 二、开启ARC后需要遵循的原则 3、不能使用id<–>void *的类型转换,因为编译器不知道这个void *是否需要retained。 4、不能使用NSAutoreleasedPool,要用@autoreleasepool {„„}来代替。 在新旧技术更替的更年期应注意:现在ARC还under NDA,没有任何开源框架可以公开支持ARC的,如果想使用此特性,在选取开源框架时应该尽量选择使用CF库较少的框架,否则手动爆开源框架的菊花会很痛苦。 【iOS中的自由桥接 【http://www.cnblogs.com/crazypebble/p/3381260.html】】 http://wenku.baidu.com/link?url=-eEFmXc76ar9IolULQjtPXCB3qYBwZRSb0vL0rfT7SmHXYH5hHBCGyVCQYIE-JWyhgvNRzdaLnv6woNdH5dYYMJbDzDudtoEmmXox_OKh7O http://blog.sina.com.cn/s/blog_4c4c79950100t3uy.html |