Objective C ARC 使用及原理
手把手教你ARC ,里面介绍了ARC的一些特性, 还有将非ARC工程转换成ARC工程的方法
ARC 苹果官方文档
下面用我自己的话介绍一下ARC,并将看文档过程中的疑问和答案写下来。下面有些是翻译,但不是全部,请一定要看一遍官方文档
- 不考虑 iOS4 的 ARC 规则
简单地说,ARC在编译时刻为代码在合适的位置加上retain 和 release. 复杂点,它还提供其它一些功能,还为解决一些问题,添加了一些关键字和功能,后面会说。
ARC强制要求的新规则
- 不可以调用dealloc, 不可以实现或者调用retain, release, retainCount, autorelease.
- 不可以使用NSAllocateObject, NSDeallocateObject
在C 结构体里不可以使用 Objective C 对象,比如下面是不允许的:
struct A {NSString *string;};
id 和 void * 之间没有自然的转换
id 指的是 Objective C 对象
void * 指的是 C指针, CGColorRef这种东西
id 和 void *之间赋值要添加 __bridge 系列关键字(后面说)不可以使用 NSAutoreleasePool 用 @autoreleasepool 替代
- 不可以使用 memory zones (NSZone). (表示没认真用过)
不可以给属性取new开头的名字, 除非给它起个不是new开头的getter. (原因不明)
// Won't work@property NSString *newTitle;// words:@property (getter=theNewTitle) NSString *newTitle;
属性声明
引入了weak, strong, unsafe_unretained, 去掉了retain, 保留了assign 其余不变
- strong 相当于 MRC(Manual Reference Counting) 的 retain
- weak 相当于 MRC 的 assign 但是 在指向的对象被销毁的时候,指针会被设置成0
assign 属性 如果是Objective C 对象,在没有特殊处理的时候,相当于strong
下面代码在 MRC 情况下是弱引用的
@interface MyClass : Superclass {id thing; // Weak reference.}// ...@end@implementation MyClass- (id)thing {return thing;} - (void)setThing:(id)newThing {thing = newThing;}// ...@end
但是在 ARC 情况下则不是 id thing; 被转换成了 id __strong thing;
所以要把上面代码的 id thing; 改为 id __weak thing; 才接近原来assign的意思.unsafe_unretained 和原来的 assign行为最像.
- 对于手动写 setter getter 又设置了修饰符的情况,我没有研究
在这里我想到好多问题
声明了属性@property (weak) NSString *member 对应的成员变量 NSString *_member (成员变量里没有写__weak)会怎样
答案是编译出错
属性@property (weak) NSString *member 和 成员变量 NSString *_member123 (成员变量里没有写__weak) @synthesize 在一起会怎样
答案是写着的时候xcode就显示出了错误
其余问题可以从上面两个问题和答案推导.
变量修饰符
下面的变量表示Objective C对象变量
__strong
默认,变量在,对象在
__weak
对象在,变量可以安全使用对象, 对象销毁,变量被设置为nil
__unsafe_unretained
对象在不在和变量无关, 变量在不在和对象无关,如果对象被销毁了,还通过变量想使用对象,会崩溃,是不安全的。(意会)
__autorelease
表示指向的对象是autorelease的, 例子如下
In non-ARC Programming, the save function looks like this:- (BOOL)save:(NSError * __autoreleasing *)myError {*myError = [[[NSError alloc] initWith…] autorelease]}In ARC Programming, the save function looks like this:- (BOOL)save:(NSError * __autoreleasing *)myError {*myError = [[NSError alloc] initWith…];}
ARC代码
NSError *error;BOOL OK = [myObject performOperationWithError:&error];
被转换成
NSError * __strong error;NSError * __autoreleasing tmp = error;BOOL OK = [myObject performOperationWithError:&tmp];error = tmp;
其实可以直接使用 NSError * __autoreleasing error; 来增加效率。
ARC根据上面那些修饰符自动生成额外的代码。
对于 __strong
NSNumber * __strong number = [NSNumber numberWithInt:13];
将会被编译成
NSNumber * number = [[NSNumber numberWithInt:13] retain];
……
// 在 number 所在的定义域外, 或者 number = nil 的时候。
[number release];
__weak 后面再说
__unsafe_unretained 应该是什么都不干 (猜测)
对于 __autorelease
NSNumber * __autorelease number = [[NSNumber alloc] initWithInt:13];
将会被编译成
NSNumber * number = [[[NSNumber alloc] initWithInt:13] autorelease];
修饰符还可以告诉编译器代码的行为
例如
NSError * __autoreleasing tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
myObject 的 performOperationWithError 使用的可能是 MRC 的代码, 也可能是 ARC的代码, 但它参数返回的肯定是一个autorelease的对象。 有了 __autoreleasing 修饰, 编译器可以知道从 performOperationWithError 方法获得 tmp 后不需要处理它的内存问题。
__weak 的实现
__weak 指针在对象被销毁的时候会被设置成 nil, 这个功能很好很强大, 避免了很多问题, 但看上去不是在某处插入个 [obj release]; obj = nil; 就可以实现了的。
具体实现在 How does the ARC's zeroing weak pointer behavior implemented?有说。
这里简单介绍一下:
ARC 的 NSObject 里大概添加了一个 weak 指针的数组,当对象销毁的时候,把数组里的变量都设置为 nil (表述不严谨,大概就是这个意思)
防止循环引用和长时间过程中被销毁(下面可能存在误导,要批判地看!)
在 MRC 中 __block id x = y; block 将不会 [x retain]; 在block执行完之后也不会 [x release];
在 ARC 中 __block id x = y; 应该等于 __strong __block id x = y; 这样会有一个retain的过程,在block被销毁的时候 [x release]。
从上面可以知道使用 __block id x = y; 而x如果拥有block的copy, 不进行处理会造成循环引用。
于是 apple 告诉我们可以这样写:
MyViewController * __block myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler = ^(NSInteger result) {[myController dismissViewControllerAnimated:YES completion:nil];myController = nil;
};
但对于多次调用的情况,上面无法达到目的。可以用 weak 关键字来替代 block (注意是替代,不是合在一起用,我对合在一起用没研究)
MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyViewController = myController;myController.completionHandler = ^(NSInteger result) {[weakMyViewController dismissViewControllerAnimated:YES completion:nil];
};
上面还是会造成问题, 如果block的代码会执行很长时间, 在那段时间 weakMyViewController 被销毁了, 那么它就变成了 nil. 程序不是崩溃就是得到错误的结果, 这样是不行的,apple 也提供了解决方法
MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyController = myController;
myController.completionHandler = ^(NSInteger result) {MyViewController *strongMyController = weakMyController;if (strongMyController) {// ...[strongMyController dismissViewControllerAnimated:YES completion:nil];// ...}else {// Probably nothing...}
};
到此表面问题基本解决。
一个古怪的行为
有代码如下:
@interface AA : NSObject
@property (strong) NSString *string;
@end@implementation AA
- (void)dealloc {NSLog(@"%@ dealloc", self.string);
}
@end- (void)testArcSimple {AA * __strong aa_weak_holder = [[AA alloc] init];AA * __weak aa_weak = aa_weak_holder;aa_weak_holder.string = @"aa_weak";void (^aBlock)(void) = ^(){NSLog(@"block : %@", aa_weak.string);};aa_weak_holder = nil;aBlock();
}
上面的输出是
block : aa_weak
aa_weak dealloc // 这个log出现在一个runloop的最后
而下面这段代码:
AA * __strong aa_weak_holder = [[AA alloc] init];
aa_weak_holder.string = @"weak";
AA * __weak aa_weak = aa_weak_holder;
aa_weak_holder = nil;
NSLog(@"aa : %@", aa_weak);
输出为
weak dealloc
aa : (null)
猜测是 aa_weak 在
void (^aBlock)(void) = ^(){NSLog(@"block : %@", aa_weak.string);};
的位置 [[aa_weak retain] autorelease] 了一遍。表示不懂。
Toll-Free Bridging
- __bridge : Objective-C 和 Core Foundation 之间的转换, 拥有权不变。
- __bridge_retained : 从 Objective-C 到 Core Foundation 的转换,由程序员负责把得到的 CFxxxRef 销毁
- __bridge_transfer : 从 Core Foundation 到 Objective-C 的转换,由ARC负责把得到的 id 销毁
__bridge_retained 的作用等于 CFBridgingRetain
__bridge_transfer 的作用等于 CFBridgingRelease
Cocoa 方法返回的 CF 对象
比如 [[UIColor greenColor] CGColor]; 编译器知道返回的 CFxxxRef 是不是需要 release 的, 当需要把它在此转换成 Cocoa 对象的时候, 不必用 __bridge __bridge_transfer 这样的修饰符, 但需要显式写出要转换成的类型, 比如:
UIColor *color = (id)[UIColor greenColor].CGColor; // 虽然这样比较无聊。
****************
来自杨先生的分享...
****************
转载于:https://www.cnblogs.com/Lxiaolong/p/4722351.html
Objective C ARC 使用及原理相关推荐
- 李洪强iOS经典面试题36-简单介绍 ARC 以及 ARC 实现的原理
李洪强iOS经典面试题36-简单介绍 ARC 以及 ARC 实现的原理 问题 简单介绍 ARC 以及 ARC 实现的原理. 考查点 ARC 是苹果在 WWDC 2011 提出来的技术,因此很多新入行的 ...
- iOS arc weak指针原理
iOS arc weak指针原理 ARC 都帮我们做了什么? weak是什么? weak是怎么实现的? 1. weak原理简介 2. weak简单测试 3. weak原理分析 3.1 weak指针帮我 ...
- ios 内存管理的理解(二)ARC概念及原理
1.什么是ARC? Automatic Reference Counting,自动引用计数,即ARC,可以说是WWDC2011和iOS5所引入的最大的变革和最激动人心的变化.ARC是新的LLVM 3. ...
- Xcode 4.2 中的Automatic Reference Counting (ARC) (转)
Automatic Reference Counting (ARC), 自动引用计数,是开发Cocoa程序时的一个编译级别的特性,用于自动内存管理. 在XCode 4.2中,使用模板新建一个工程,该工 ...
- Xcode 4.2 中的Automatic Reference Counting (ARC)
Automatic Reference Counting (ARC), 自动引用计数,是开发Cocoa程序时的一个编译级别的特性,用于自动内存管理. 在XCode 4.2中,使用模板新建一个工程,该工 ...
- 【iOS开发-ARC实现-源码略读】
文章目录 前言 简单了解Clang 和 llvm 关于查看Clang编译的源代码 __strong **`objc_opt_new`** **`objc_storeStrong`** isa指针 ** ...
- ARC算法分析与实现
ARC算法分析与实现 ARC算法是2003年提出的缓存替换算法,是众多针对LRU算法的改良算法之一. 本文仅从模拟实现角度分析ARC算法,可以说就是解释ARC算法的内容,而不会将重点放在ARC算法的原 ...
- Xcode非ARC项目转ARC,ARC项目中支持非ARC也就是共存
1. Xcode非ARC项目转ARC 选中工程>Edit > Refactor > Convert to Objective -C ARC 然后就是下一步,save保存 eable ...
- iOS 知识点整理 (持续更新...)
整理了些iOS相关的基础问题,每个问题可能会再写些扩展,需要具体了解可以看题目下方的链接 如有错漏,欢迎指出,谢谢 一.Swift 1.给一个数组,要求写一个函数,交换数组中的两个元素(swift可用 ...
最新文章
- java 获取第一帧_java获取视频的第一帧
- python爬虫代码1000行-最精简的爬虫 --仅需4行代码(python)
- Unicode与UTF-8互转(C语言实现)
- JPA的entityManager的find、getReference、persisit、remove方法的使用
- boost::system::generic_category相关的测试程序
- js验证开始日期不能大于结束日期_js前台判断开始时间是否小于结束时间
- 【蓝桥杯真题】地宫取宝(搜索-记忆化搜索详解)
- 设置线程当天十二点执行_这份JAVA多线程笔记真的是细节满满,几乎全是你工作能用到的干货...
- torch.randn【返回从标准正态分布(均值为0,方差为1,即高斯白噪声)中抽取的一组随机数】
- vux在ISO中异常 this.$vux.confirm.show
- python中使用连续关系运算符_解释一下Python中的关系运算符
- matlab中的pzmap的意思,Matlab 学习
- 无人驾驶车辆轨迹跟踪控制文献分享(1)
- JAVA获取CKplayer真是地址_[Java教程]使用CKplayer插件在网页中嵌入视频的方法(常用笔记2)...
- TAS5754应用笔记
- 正点原子阿波罗STM32F7-红外遥控原理及代码
- 阿里、腾讯裁员,2022金三银四Android开发该何去何从?
- 深度学习手记(八)之PTB实现LSTM模型
- 【067】Color Hunter-用图片搜索配色方案
- 怎么开通附近小程序-微信小程序开发-视频教程20