iOS——引用计数

引用计数

IOS中手动管理内存方式是通过引用计数来实现内存的管理,当对象调用alloc方法,引用计数置为一,以后每一次retain,引用计数加一,

对应的,release方法,会将对象的引用计数减一,当对象的引用计数为0时,系统将回收对象的内存。

其中值得注意的是调用add方法时也会retain
OC 语言使用引用计数来管理内存每个对象都有个可以递增或递减的计数器,如果想某个对象继续存活,那就递增其引用计数,用完之后,就递减其计数,计数变为0,就销毁。
当使用alloc new copy等方法的时候引用计数设置为1
之后每一次使用retain(比如add方法,持有对象)引用计数就会加1,这代表多了一个对象在使用这个变量,其引用计数就会增加。
使用release方法,其引用计数就会减1,当引用计数减少为0的时候就代表没人用他了,这时候系统就会调用dealloc方法来销毁其对象

非自己生成的对象,自己也能持有

//取得非自己生成并持有的对象
id obj = [NSMutableArray array];

//NSMutableArray类变量被赋值给obj,但是obj自己并不持有该对象。
[obj retain];

//现在obj持有该对象

//通过retain方法,非自己生成的对象跟用alloc方法生成并持有的对象一样。

无法释放非自己持有的对象

对于用alloc\ new\ copy \ mutableCopy方法生成并持有的对象,或是用retain方法持有的对象,由于持有者是自己,所以在不需要该对象时需要将其释放,而由此之外所得到的对象绝对不能释放。若在应用程序中释放了非自己所持有的对象就会造成崩溃。

- (id)object {
  id obj = [[NSObejct alloc] init];
  //自己持有对象
  
  [obj autorelease];
  //取得对象存在,但自己不持有对象
  return obj;
}

//通过autorelease方法,可以使取得的对象存在,但自己不持有对象

id obj1 = [obj0 object];
//取得对象存在,但自己不持有对象

[obj1 release];
//释放了非自己持有的对象!应用程序会崩溃


release 与autorelease

autorelease

autorelease即“自动释放”,是OC的一种内存自动回收机制,可以将一些临时变量通过自动释放池来回收统一释放。自动释放池销毁的时候,池子里面所有的对象都会做一次release操作

那么,autorelease释放与简单的release释放有什么区别呢?

调用 autorelease 方法,就会把该对象放到离自己最近的自动释放池中,即:使对象的持有权转移给了自动释放池,调用方拿到了对象,但这个对象还不被调用方所持有。当自动释放池销毁时,其中的所有的对象都会调用一次release操作。
本质上,区别在于autorelease 方法不会改变调用者的引用计数,它只是改变了对象释放时机,不再让程序员负责释放这个对象,而是交给自动释放池去处理 。

autorelease 方法相当于把调用者注册到 autoreleasepool 中,ARC环境下不能显式地调用 autorelease 方法和显式地创建 NSAutoreleasePool 对象,但可以使用@autoreleasepool { }块代替(并不代表块中所有内容都被注册到了自动释放池中)。

对于所有调用过autorelease实例方法的对象,在废弃NSAutoreleasePool对象时,都将调用release实例方法。

自动释放池使用场景

  • 循环中创建了许多临时对象,在循环里使用自动释放池,用来减少高内存占用。

MRC和ARC

我们想要彻底理解属性关键字,那首先我们先来简单了解一下,MRC和ARC

MRC

MRC:Manul Reference Counting(手动引用计数)

需要手动管理内存,即手动添加release/retain等内存管理代码,否则,会造成内存泄露

涉及方法

  • alloc/new/copy/mutableCopy:生成对象并自己持有,引用计数+1(从0变为1)
  • retain :持有对象,使对象的引用计数加1
  • release : 释放对象,使对象的引用计数减1
  • retainCount : 获取当前对象的引用计数值
  • autorelease : 当前对象会在autoreleasePool结束的时候,调用这个对象的release操作,进行引用计数减1
  • dealloc : 在MRC中若调用dealloc,需要显示的调用[super dealloc],来释放父类的相关成员变量

关于retainCount

我们在MRC中,有时可能会想要打印引用计数,但retainCount方法并不是很有用,由于对象可能会处于自动释放池中,这会导致打印的引用计数并不精准,而且其他程序库也很有可能自行保留或释放对象,这都会扰乱引用计数的具体值。
查阅了一下官方的文档,第一句就是“Do not use this method.”,后面给出了说明,因为Autorelease pool的存在,对于内存的管理会相当复杂,retainCount就不能用作调试内存时的依据了在这里插入图片描述
在这里插入图片描述

ARC

ARC:Automatical Reference Counting(自动引用计数)

iOS中的垃圾回收机制跟其它语言不同,iOS的内存管理机制是编译器(Xcode)帮我们添加内存管理的代码,不用像MRC那样,手动添加retain/release代码

  • ARC进行自动内存管理的原则是:判断是否还有强指针指向当前对象
    在非MRC模式下,不能调用release,retain,retainCount等方法,也无法在dealloc中调用[super dealloc]方法。

其次:在ARC下不要手动的为@autoreleasepool代码块内部对象添加autorelease,ARC会自动把@autoreleasepool代码块中创建的对象加入自动释放池中

修饰符

当ARC有效时,id类型和对象类型必须附加所有权修饰符,一共有如下四种。

  • __strong
  • __weak
  • __unsafe_unretained(查阅资料的时候,听说这个好像不咋用了,不用考虑)
  • __autoreleasing

strong

__strong修饰符是id类型和对象类型默认的所有权修饰符。

id obj  = [[NSObject alloc] init];
  
//在没有明确指定所有权修饰符时,默认为__strong
id __strong obj = [[NSObject alloc] init];

不论调用哪种方法,强引用修饰的变量会持有该对象,如果已经持有则引用计数不会增加。
__strong修饰符表示对对象的强引用。持有强引用的变量在超出其作用域时被废弃,随着强引用的失效,引用的对象会随之释放。

__weak修饰符

弱引用表示并不持有对象,当所引用的对象销毁了,这个变量就自动设为nil。

MRC手动内存管理就是每一次对retain,alloc或者new的调用,就需要对其release或者autorelease.而ARC所做的无非就是在合适的时机帮我们release或者autorelease,无需程序员手动把这些代码敲上去,极大的节省了时间,并且避免因忘记释放造成的内存泄露。
在ARC中,所有实例变量和局部变量默认情况下都是strong类型,类似于MRC中的retain.只要某个对象被任一strong指针指向,那么它将不会被销毁,相反的,如果对象没有被任何strong类型的指针指向,那么就将被销毁. 与strong相对是weak,weak类型的指针可以指向对象,但是不会持有该对象,当对象被销毁,weak会自动指向nil。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值