MRC转ARC注意事项和存在的问题
2014-01-13 15:34
405 查看
转载请注明出处:http://blog.csdn.net/cywn_d/article/details/18222671
1.删除所有retain,release和autorelease。
2.把原来property写retain和assign的地方替换成strong或者weak.
3.MRC需要自己retain一个想要保持的对象,而现在不需要了。现在唯一要做的是用一个指针指向这个对象,只要指针没有被置空,对象就会一直保持在堆上。当将指针指向新值时,原来的对象会被release一次。
4.必须在合适的地方把strong指针手动设置到nil。
以下两行代码,如果是MRC,那么array[0]对象在remove后将销毁,而在ARC下,由于对象是strong的,所以obj持有array[0]的那个对象,即使array将array[0]对象移除,该对象依然被obj持有。
id obj = [array objectAtIndex:0];
[array removeObjectAtIndex:0];
5.dealloc并没有做除了release和super dealloc之外的任何事情,直接删除整个delloc方法就可以了。
6.有些地方要进行桥接转换的,要根据情况加上bridge,bridge_transfer和__bridge_retained三个关键字中的一个。
7.不使用ARC的文件,在Build Phases-Compile Sources的文件中双击,输入-fno-objc-arc。
8.ARC forbids Objective-C objects in structs or unions
ARC机制下,struct里面不能定义OC对象。在出错的地方添加__unsafe_unretained,但是可能会产生问题。
9.关于MRC与ARC混编译时引用框架可能产生的问题
MRC和ARC混编译主要的解决方法是使用 -fno-objc-arc编译标记。
普通的项目可以通过设置-fno-objc-arc编译标记,成功使用MRC和ARC混编译。
但是有一种情况不可以:
就是在项目里引用了一个framework的.h头文件,这个头文件有写地方不符合ARC规范,可能有两种解决方法,
第一种是把这个头文件不符合ARC的地方改成符合ARC,但是,这可能会影响到这个框架里面.m文件的使用。我们无法看到里面的细节,所以也无法确认会不会存在问题。
第二种是把这个头文件的.m文件设置为非ARC,即加上 -fno-objc-arc编译标记。可是框架里面的.m文件是不可见的,我们无法对其进行设置。可能只需要把引用了这个头文件的.m文件设为非ARC就可以,还未测试。
10.关于桥接转换:
自由桥接对象:在Cocoa框架中,有很多顶层对象对底层的抽象,而在使用中我们往往可以不加区别地对这两种对象进行同样的对待,这类对象即为可以”自由桥接”的对象(toll-free
bridged)。NSURL和CFURLRef就是一对好基友好例子,在这里其实CFURLRef和NSURL是可以进行替换的。
Core Foundation最聪明的地方体现在它能和Foundation无障碍地交换数据。比如说,任何接受
cast)是给编译器的指令,告诉它如何处理自动引用计数。
在很多情况下,只需要使用
这其实是告诉编译器什么都别做。它只要简单地把
反过来也一样:
只要没有Core Foundation的内存管理介入,
怎样才能正确转换
这个函数把所有权从Core Foundation转移到ARC。在这个过程中,它把引用计数减1以平衡
在把一个对象从ARC转移到Core Foundation时要用
桥接函数也可以写成类型转换的形式,如下:
函数形式更简短,也更容易理解。
Foundation之间转移时。它们不是
Foundation转移到ARC,就不应该再使用Core Foundation变量了,应该将其置为
Foundation,要马上把ARC变量设置为
自由桥接不仅可以方便地在C和Objective-C之间转移信息,还能让Cocoa开发者用上某些只有Core Foundation有(而Objective-C没有等价功能)的函数。比如,
一些不显式支持自由桥接的类型也能桥接为
Foundation对象(即使没有等价的Cocoa类),如下例所示:
自由桥接是用相当直观的方式实现的。每个Objective-C对象结构体都是以一个指向
Core Foundation不透明类型则以一个
Foundation函数调用。比如,
如果没有显式桥接类,那么
为了支持把Objective-C类传递给Core Foundation函数,所有公开的自由桥接函数看起来都类似如下所示:
Foundation桥接类,那就把调用传给真正的Core Foundation函数;否则,就把调用转化为Objective-C消息(在本例中是
参考:
http://wiki.eoe.cn/page/iOS_pptl_artile_30358.html iOS中自由桥接
http://www.onevcat.com/2012/06/arc-hand-by-hand/ 手把手教你ARC——iOS/Mac开发ARC入门和使用
1.删除所有retain,release和autorelease。
2.把原来property写retain和assign的地方替换成strong或者weak.
3.MRC需要自己retain一个想要保持的对象,而现在不需要了。现在唯一要做的是用一个指针指向这个对象,只要指针没有被置空,对象就会一直保持在堆上。当将指针指向新值时,原来的对象会被release一次。
4.必须在合适的地方把strong指针手动设置到nil。
以下两行代码,如果是MRC,那么array[0]对象在remove后将销毁,而在ARC下,由于对象是strong的,所以obj持有array[0]的那个对象,即使array将array[0]对象移除,该对象依然被obj持有。
id obj = [array objectAtIndex:0];
[array removeObjectAtIndex:0];
5.dealloc并没有做除了release和super dealloc之外的任何事情,直接删除整个delloc方法就可以了。
6.有些地方要进行桥接转换的,要根据情况加上bridge,bridge_transfer和__bridge_retained三个关键字中的一个。
7.不使用ARC的文件,在Build Phases-Compile Sources的文件中双击,输入-fno-objc-arc。
8.ARC forbids Objective-C objects in structs or unions
ARC机制下,struct里面不能定义OC对象。在出错的地方添加__unsafe_unretained,但是可能会产生问题。
9.关于MRC与ARC混编译时引用框架可能产生的问题
MRC和ARC混编译主要的解决方法是使用 -fno-objc-arc编译标记。
普通的项目可以通过设置-fno-objc-arc编译标记,成功使用MRC和ARC混编译。
但是有一种情况不可以:
就是在项目里引用了一个framework的.h头文件,这个头文件有写地方不符合ARC规范,可能有两种解决方法,
第一种是把这个头文件不符合ARC的地方改成符合ARC,但是,这可能会影响到这个框架里面.m文件的使用。我们无法看到里面的细节,所以也无法确认会不会存在问题。
第二种是把这个头文件的.m文件设置为非ARC,即加上 -fno-objc-arc编译标记。可是框架里面的.m文件是不可见的,我们无法对其进行设置。可能只需要把引用了这个头文件的.m文件设为非ARC就可以,还未测试。
10.关于桥接转换:
自由桥接对象:在Cocoa框架中,有很多顶层对象对底层的抽象,而在使用中我们往往可以不加区别地对这两种对象进行同样的对待,这类对象即为可以”自由桥接”的对象(toll-free
bridged)。NSURL和CFURLRef就是一对好基友好例子,在这里其实CFURLRef和NSURL是可以进行替换的。
Core Foundation最聪明的地方体现在它能和Foundation无障碍地交换数据。比如说,任何接受
NSArray的函数或方法同样也接受
CFArray,只要经过一次桥接转换即可。**桥接转换**(bridge
cast)是给编译器的指令,告诉它如何处理自动引用计数。
在很多情况下,只需要使用
__bridge修饰符,如下代码所示:
1 2 | NSArray *nsArray = [NSArray arrayWithObject:@"Foo"]; printf("%ldn", CFArrayGetCount((__bridge CFArrayRef)nsArray)); |
nsArray转换为
CFArrayRef,并传给
CFArrayGetCount。
nsArray的引用计数没有变化。
反过来也一样:
1 2 | CFMutableArrayRef cfArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFArrayAppendValue(cfArray, CFSTR("Foo")); NSLog(@"%ld", [(__bridge id)cfArray count]); CFRelease(cfArray); |
__bridge转换就管用。在上面的例子中,我们没有把结果赋给变量或者返回结果。然而,考虑下面这种情况:
1 2 | - (NSString *)firstName { CFStringRef cfString = CFStringCreate...; return (???)cfString; } |
cfString?在ARC之前,要把它转换成
NSString,然后调用
autorelease。有了ARC,就无法调用
autorelease了,而ARC不知道
cfString还有一个来自
CFStringCreate...的保留。还是得用桥接转换,只不过这次是以下例所示的函数:
1 | return CFBridgingRelease(cfString); |
CFStringCreate...。必须用桥接转换才能做到这一点,调用
CFRelease会在返回对象前就销毁对象。
在把一个对象从ARC转移到Core Foundation时要用
CFBridgeRetain,它会把引用计数加1,如下代码所示:
1 2 | CFStringRef cfStr = CFBridgingRetain([nsString copy]); nsString = nil; // 所有权现在归cfStr了 ... CFRelease(cfStr); |
1 2 | NSString *nsString = CFBridgingRelease(cfString); NSString *nsString = (__bridge_transfer id)cfString; CFStringRef cfString = CFBridgingRetain(nsString); CFStringRef cfString = (__bridge_retained CFTypeRef)nsString; |
CFTypeRef是指向Core Foundation的通用指针,而
id是指向Objective-C对象的通用指针。这里也可以用具体的类型,像
CFStringRef和
NSString*。
函数形式更简短,也更容易理解。
CFBridgingRelease和
CFBridgingRetain应该只用在对象在ARC和Core
Foundation之间转移时。它们不是
CFRetain和
CFRelease的替代品,也不是“欺骗”编译器给Objective-C对象施加额外的
retain或
release操作的方法。一旦对象从Core
Foundation转移到ARC,就不应该再使用Core Foundation变量了,应该将其置为
NULL。相反,当从ARC转换到Core
Foundation,要马上把ARC变量设置为
nil。这里已经把所有权从一个变量转到了另一个变量,因此旧变量应该无效。
自由桥接不仅可以方便地在C和Objective-C之间转移信息,还能让Cocoa开发者用上某些只有Core Foundation有(而Objective-C没有等价功能)的函数。比如,
CFURLCreateStringByAddingPercentEscapes提供的转换功能比它所对应的
NSURL的
stringByAddingPercentEscapesUsingEncoding:方法强大得多。
一些不显式支持自由桥接的类型也能桥接为
NSObject。这意味着能在Cocoa容器对象中存储Core
Foundation对象(即使没有等价的Cocoa类),如下例所示:
1 2 | CFTreeContext ctx = {0, (void*)CFSTR("Info"), CFRetain, CFRelease, CFCopyDescription}; CFTreeRef tree = CFTreeCreate(NULL, &ctx); NSArray *array = [NSArray arrayWithObject:(__bridge id)tree]; CFRelease(tree); NSLog(@"%@", array); |
Class的ISA指针开始的:
1 2 | typedef struct objc_class *Class; typedef struct objc_object { Class isa; } *id; |
CFRuntimeBase开始,而它的第一个元素也是ISA指针:
1 2 | typedef struct __CFRuntimeBase { uintptr_t _cfisa; uint8_t _cfinfo[4]; #if __LP64__ uint32_t _rc; #endif } CFRuntimeBase; |
_cfisa指向自由桥接的Cocoa类,这是等价的Cocoa类的子类,它们会把Objective-C方法调用转发为等价的Core
Foundation函数调用。比如,
CFString桥接到私有的自由桥接类
NSCFString。
如果没有显式桥接类,那么
_cfisa指向
__NSCFType,这是
NSObject的子类,可以转发
retain和
release等类似调用。
为了支持把Objective-C类传递给Core Foundation函数,所有公开的自由桥接函数看起来都类似如下所示:
1 2 | CFIndex CFStringGetLength(CFStringRef str) { CF_OBJC_FUNCDISPATCH0(__kCFStringTypeID, CFIndex, str, "length"); __CFAssertIsString(str); return __CFStrLength(str); } |
CF_OBJC_FUNCDISPATCH0检查
_cfisa指针。如果对于给定的
CFTypeID,它匹配Core
Foundation桥接类,那就把调用传给真正的Core Foundation函数;否则,就把调用转化为Objective-C消息(在本例中是
length,以C字符串的形式给出)。
参考:
http://wiki.eoe.cn/page/iOS_pptl_artile_30358.html iOS中自由桥接
http://www.onevcat.com/2012/06/arc-hand-by-hand/ 手把手教你ARC——iOS/Mac开发ARC入门和使用
相关文章推荐
- 《设计搜索体验:搜索的艺术与科学》
- asp.net访问母版页控件方法
- Ext中的样式控制
- Posix标准中的timer和AIO
- WPF好文分享
- hive修改表模式<转>
- EBS OAF开发中属性集(Attribute Set)的介绍和手工实现
- 【转载】Shared Configuration
- 数据结构 《2》----基于邻接表表示的图的实现 DFS(递归和非递归), BFS
- linux下实现VPS web和mysql数据的备份脚本
- STM32_USB之完全双缓存(包括发送和接收) -- 更新中断处理
- 【jdk源码解析三】java.util.Hashtable
- warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory
- signal
- 数据结构 《2》----基于邻接表表示的图的实现 DFS(递归和非递归), BFS
- [LeetCode]Simplify Path
- JAVA基础——模板设计方法
- LeetCode - Linked List Cycle
- js jquery分别实现动态的文件上传操作按钮的添加和删除
- eclipse启动或者运行过程中tomcat出现内存溢出错误 java.lang.OutOfMemoryError: PermGen space