捋捋ARC
来源:互联网 发布:各种淘宝助理版本下载 编辑:程序博客网 时间:2024/06/04 08:20
定义:wiki
捋一捋ARC,或者说看看iOS的内存管理机制
引用计数:
引用计数是来用帮助oc进行内存回收的机制,如上图表示的代码类似于
NSObject *p1 = [NSObject new];NSObject *p2 = p1;NSObject *p3 = p1指针指向了同一块内存区域,即对象存放的区域,用引用计数来描述的话,此刻对象的引用计数为3。
在引用计数为0时该内存区域将被回收用于存储其他。
MRC(manual reference counting)/MRR(manual retain-release):手动引用计数管理
既然是手动,说明引用计数不会像上面的代码一样NSObject *p2 = p1就让obj的引用计数加一。需要手动调用方法retain来增加引用计数
即 NSObject *p2 = [p1 retain];
相应的也不会在p2 = nil时减少引用计数,而需要调用release方法
即 [p2 release];
其他:
autorelease:调用后,对象会在当前的autoreleasepool结束时将引用计数减1
对象delloc:在dealloc下需要将不再被使用的指针调用release。
那么在ARC的时代下这些方法是怎么做到对开发者不可见的呢
ARC下系统会在编译时期自动加入对应的retain、release
可以考虑以下场景:
1.无返回值的方法:
ARC下文章开头的代码实际上是如下形式:
NSObject *p1 = [NSObject new];NSObject *p2 = [p1 retain];NSObject *p3 = [p1 retain]//when no longer used[p3 release];[p2 release];[p1 release];
2.有返回值的方法:
ARC下:
- (NSString *)genSomeObj{ NSString *a = [[NSString alloc]initWithFormat:@"%@",@"ARC"]; return a;}MRC下:
- (NSString *)genSomeObj1{ NSString *a = [[NSString alloc]initWithFormat:@"%@",@"ARC"]; return a;}- (NSString *)genSomeObj2{ NSString *a = [[NSString alloc]initWithFormat:@"%@",@"ARC"]; return [a autorelease];}- (void)main{ NSString *s1 = [self genSomeObj1]; [s1 release]; NSString *s2 = [self genSomeObj2]; //由于autorelease,不需要调用[s2 release]}
ARC有一个规定:以new、alloc、copy、mutableCopy开头的方法需要由调用者主动管理内存
即同样是产生一个string的方法genSomeObj和newSomeObj,在ARC下被系统补充后的实现如下:
- (NSString *)genSomeObj{ NSString *a = [[NSString alloc]initWithFormat:@"%@",@"ARC"]; return [a autorelease];}- (NSString *)newSomeObj{ NSString *a = [[NSString alloc]initWithFormat:@"%@",@"ARC"]; return a;}
调用newSomeObj方法的地方需要生成的指针不再使用时调用一次release(当然也是系统去调)
由于genSomeObj调用了autorelease,假设调用生成的指针还要继续指向该对象(需要保留该对象),那么还需要在此retain,例如
- (void)main{ NSString *b = [[self genSomeObj]retain]; //do something with b}...{... [b release];...}
3.dealloc
ARC的dealloc将调用实例变量的release(不同于MRC下开发可以随时release,所以MRC下之需要开发自己写未被release的对象即可)
4.ARC下提供的property:
property的目的是为实例变量提供了更方便的访问方式,系统会为声明为property的obj生成实例变量_obj,并且提供默认的getter\setter
假设是MRC的环境,setter会是怎样的呢?
- (void)setObj:(NSObject *)obj{ [_obj release]; [obj retain]; _obj = obj;}
为什么会这样?
1.实例变量_obj可能会有旧值,此时它需要指向新的对象地址的,所以需要将之前对象的引用计数减1(如果_obj之前指向了某个对象)
2.新对象马上要被_obj引用,所以需要obj增加引用计数
3.开始引用(赋值操作)
property是可以有好几种形容词的,说下最常见的nonatomic,strong,weak,assgin
nonatomic:字面意思表示对象操作不具有原子性,如果不加这个形容词,那么对象的访问会被加锁
strong:属性赋值时会自动retain
weak:弱引用不会增加引用计数、会在指向的对象将要销毁时自动置为nil,防止也指针,具体可见weak的详细介绍
assgin:一般用于修饰基本类型,如果修饰对象,是不会自动进行retain操作的(不加引用计数)
5.block的使用
block是c/c++里闭包的实现,关于闭包的理解见阮一峰的blog
block分为NSStackBlock\NSGlobalBlock\NSMallocBlock:栈block,全局block,堆bock,其中栈block存储于栈,其他存储于堆
一个block在创建时属于stackblock还是globalblock,取决于block内是否使用了外部变量,在没有使用外部变量时为globalblock,有globablock的好处是对于它的很多方法都不需要实际处理,例如copy操作。
但在ARC下其实很少会使用stackblock,只要将新创建的block赋值指针,ARC下会自动进行copy操作,stackblock即化身为mallocblock。
MRC下入若执行以下代码
@interface MRCObj(){ void(^block)();}@end@implementation MRCObj- (void)test{ NSInteger i= 0; block = ^(){__unused NSInteger b = i;};}- (void)testBlock{ block();}@end//somewhere{ MRCObj *mo = [MRCObj new]; [mo test]; [mo testBlock];}会由于block变量指向了一个stackblock,而方法结束后stackblock释放,再次调用则引起崩溃。
所以在MRC下则需要主动进行Block_copy、Block_release操作例如,ARC下则如上所述会自行拷贝
Tips:
亲自测试MRC运行情况可在Build Phase的Compile Sources内将该文件设为-fno-objc-arc
- 捋捋ARC
- ARC
- ARC
- arc
- ARC
- ARC
- ARC
- ARC
- arc
- ARC
- ARC
- arc
- arc
- ARC
- arc
- ARC
- ARC
- arc
- 为什么TCP连接需要三次握手分开需要四次握手?
- Spring学习笔记之构建Spring Web应用程序
- java组件更改颜色方法
- File readLine()
- 几种常用的hash算法
- 捋捋ARC
- Java多线程速记
- 孤单之人的学习日记 02
- c/c++ g++默认编译调用成功,O2优化却发生Segmentation fault
- 遗漏问题
- 一小波前端知识来了
- wxpython
- NIO与传统IO的区别
- 【leetcode】215. Kth Largest Element in an Array