可能的误区和一些小技巧
ARC听起来像自动内存管理,效率是不是比手动低呢?
ARC跟垃圾回收那种机制不同,根据Apple的说法,ARC的效率反倒高,如果你看过ARC的原理就知道了怎么回事了,具体参考文档吧。至于效率为什么会高,主要是之前通过autorelease释放的东西都是随着runloop在autorelease pool中一起释放的,而开启了ARC后,很多之前要autorelease的东西直接就通过类似手动管理的方式释放掉了,根本没放到autorelease pool中,从而提升了效率。那么效率提高了多少,反正我是感觉不出来,一般情况下应该微乎其微吧,但至不会降低效率。
我费了不少时间弄明白了内存管理的机制,用了ARC之前的努力岂不白费了?
- 最开始我也比较排斥ARC,认为开启ARC,写代码不就没有什么技术含量了么?实际上使用ARC更需要我们对内存管理机制有深刻的认识,在没有ARC之前,即使我们不懂内存管理,我们程序照样跑,大不了我不写release,内存泄漏就泄漏呗!开启了ARC之后如果不懂内存管理机制,你连哪里出现问题了可能都不知道。
- 此外ARC只是对NSxxx,UIxxx这些Objective-C对象有效,那些CGxxxx,CFxxxx这种Core Fundation对象的还是需要xxxxretain(),xxxxrelease()的,不懂内存管理机制很容易在Obj-C和Core Fundation转换的时候出现问题,记得有个老外的文章分析使用ARC之后,对象的生命周期出户意料的短,他举例的代码大概是这样的
1 | CGColorRef cgcolor = [UIColor blackColor].CGColor; |
2 | UIView *view = [UIView alloc] initWithFrame:frame]; |
3 | [view.layer setBackgroundColor:cgcolor]; |
- 在最后那行就会出现EXC_BAD_ACCESS,原因是第二行取得color的CGColor之后,color对象就被施放了。然后又汇编又怎么的分析了一通得出结论:color的生命周期短,之后还给出了几个fix我就不贴了,我只想说这根本不是生命周期短不短的问题,这就是他没好好看看Transitioning to ARC Release Notes这篇文档,像他这么个写法根本就是错的,不遵照内存管理肯定最后会有EXC_BAD_ACCESS。
- ARC同样也不能处理retain cycle问题,综上也就是说想借ARC来免去学习内存管理是完全不可行的。
我的应用要向下兼容,所以暂时用不了ARC。
- ARC是兼容iOS4.0+的,现在4.0以下的机器还有么,5.0以下的都挺少了吧,有也不用管了吧,苹果不能降级的好处就在这里,至于在5.0以下系统中不能使用weak,这个至少在我接触的各种情形中unsafe_unretained完全可以替代。
那些开源的Framework没有提供ARC版怎么办?
- 可以针对单独的文件设置是否使用ARC,不使用的话就加上 -fno-objc-arc 标记,具体参考文档Transitioning to ARC Release Notes最后面。
有没有将现有代码转换成ARC的方法?
- 菜单上 Edit>>Refactor>>Convert to Obj-c ARC… 之后按提示走就可以了,有时候可能很麻烦,一些开源Framework也几乎转不成功,这时需要按4中的方法,为那些不方便转换的文件提前设置好 -fno-objc-arc 标记,之后再Convert。
综合这一阵的体会,除了兼容4.0之前的系统外,基本上找不到任何一个不使用ARC的理由,实际情况中,开启ARC也确实方便了不少,不用费半天劲去再dealloc里面添加各种release,block的使用也更随意了,有ARC基本也不用担心内存泄漏问题,开发效率有了很大提高。
一,注意事项
1.不可以使用retain,retainCount,release,autorelease 用@select()这样的调用也不行.属性命名不能以new开头。
2.若重写一个类子类的dealloc,不应调用[super dealloc],当然也不用写什么release释放一些什么对象,只是处理一些你觉得必要处理的事情吧,比如中止一个还没有完成的网络请求.
3.不能使用NSAllocateObject和NSDeallocateObject
4.你不能在c结构中使用对象,更好的方式是使用Objective-c类来代替.
5.在id和void*之间不能隐私转换,必须指明相应转换的生命周期。
6.不能使用NSAutoreleasePool对象,ARC使用@autoreleasepool{}块代替。
7.不能使用内存块,NSZone已经不需要使用了,现在运行时已经忽略之。
二.基本关键字
声明变量就会默认赋值nil的.
1 | #相当于retain,在不再使用的时候被释放 (默认) |
4 | #与assign很像,不同在于如果指向的数据被释放了,那么这个指向nil |
7 | #相当于assign,指向的数据如果被释放,这个指向原来的地址 |
这些可以定义局部变量__strong __weak __unsage_unretained
1 | #标明传给函数的(id*)型参数是自动释放的,(函数中(id*)型参数默认的也是这种类型) |
1.__autoreleasing不能修饰全局变量,不能修饰类的属性.只能再函数块中用来定义变量,相当与__strong,一旦赋值,直到生命周期结束释放.
2.对于(id*)型函数参数,默认是__autoreleasing型的,这是由1知道只能传局部变量给函数做实参;如果用__weak修饰,那么会在结束时使的实参为nil,没有意义;__strong修饰可以用全局变量,类的属性值作为参数,其他与__autoreleasing没有区别
demo1
1 | NSString __weak *string = [[ NSString alloc] initWithFormat:@"First Name: %@", @"aaa"]; |
2 | NSLog (@"string: %@", string); |
4 | #编译器会给出警告.程序第一句申请了一个内存,赋值给string,然后weak引用的string并没有retain这个内存 |
5 | #这个内存赋值后在块内并没有再次使用,他的周期就存在与赋值语句内部,所以释放,然后string指向的内存被释放所以他是nil. |
demo2
01 | @property ( nonatomic ,strong) NSString * stringA; |
02 | @property ( nonatomic ,weak) NSString * stringB; |
04 | self .stringA = @"string A"; |
05 | self .stringB = stringA; |
07 | NSLog (@"%@",stringB); |
10 | self .stringA = [ NSString stringWithFormat:@"%@",@"string A"]; |
11 | self .stringB = stringA; |
13 | NSLog (@"%@",stringB); |
17 | self .stringA = [[ NSString alloc] initWithFormat:@"%@",@"string A"]; |
18 | self .stringB = stringA; |
20 | NSLog (@"%@",stringB); |
��
这三个函数分别输出什么呢?都是”string A”.那么在函数执行完之后呢?stringB对应的值是什么?
a:string A// 常字符串存储在静态存储区,stringB指向的那个不会被释放
b:(null)// stringA指向那块自动释放的内存再块结束时释放
c:(null)// stringA就是指向分配字符串的内存,赋予nil会释放那块内存
btw:第一次试验的时候块内就已经是块外的值了.囧..
三.Toll-Free Bridging
Core Foundation 对象与Objective-c对象之间的赋值,函数调用参数相互转化时需要用到的关键字
1 | #简单赋值,不会影响两边对象的retain count. |
demo3
03 | CFStringRef coreFoundationString = CFStringCreateWithCString(CFAllocatorGetDefault(),"C String", kCFStringEncodingUTF8); |
04 | id unknownObjectType = (__bridge id )coreFoundationString; |
05 | CFStringRef anotherString = (__bridge_retained CFStringRef)unknownObjectType; |
06 | NSString *objCString = (__bridge_transfer NSString *)coreFoundationString; |
07 | NSLog (@"String = %@", objCString); |
09 | CFRelease(anotherString); |
四.其他
1.开关 :-fobjc-arc 和 -fno-objc-arc 编译标识来指明单个文件的方式.
整个工程转向ARC可以选中工程->菜单edit->refactor->convert to Objective-c ARC
2.除了nib的Top-Level(main nib文件里面的对象,除了File’s owner 和 Application)对象,其他的IBOutlet最好都是weak型的.
3.如果一定要实现类的自定义的retain和release,那么同时也要在类中加入
1 | -( BOOL )supportsWeakPointers { return NO ; } |
4.在c型的结构中使用objective-c对象
使用void*代替id;或者使用__unsage_unretained 修饰objective-c对象
5.不能zeroing-weak引用的类有
1 | SATSTypesetter, NSColorSpace , NSFont , NSFontManager , NSFontPanel , NSImage , NSMenuView , NSParagraphStyle , NSSimpleHorizontalTypesetter , NSTableCellView , NSTextView , NSViewController , NSWindow , and NSWindowController . |
他们的对象,作为属性,使用assign代替weak;作为变量,使用__unsafe_unretained代替__weak。
ARC下也不能weak引用NSHashTable, NSMapTable, or NSPointerArray。
6. __block修饰的变量默认也是__strong引用的.
转载自 链接 链接
官网文档 Transitioning to ARC Release Note 中文版
Copyright © 2010 c小淡のп_п_п 转载请著名出处
推荐给您的文章:
- [objective-c] ARC 对象转换
- [objective-c] 分类(category)和扩展(extension)
- [objective-c] wwdc2012 objc新特性
- [objective-c] 消息, category和protocol
- [tutorial] programming with openGLES chapter 01
arc , autorelease , objective-c , release , retain , strong , week , __bridge
From: http://www.stylejar.com/archives/objective-c-arc-%E8%A1%A5%E5%85%85.html