引用计数是一个简单而有效的管理对象生命周期的方式。不管是OC还是Swift语言,其内存管理方式都是基于引用计数的。曾经有一个面试官问我:iOS内存管理的原理是什么?我当场懵逼了,不知道他问的是什么意思,后来想了一下,不就是引用计数吗。
什么是引用计数?引用计数的原理 引用计数可以有效的管理对象的生命周期,当我们创建一个新对象的时候,他(该对象所在的内存块)的引用计数为1,当有一个新的指针指向这个对象时,我们将其引用计数加1,当某个指针不在指向这个指针式,我们将其应用计数减1,当对象的引用计数变为0时,说明这块内存不在被任何指针指向,这个时候系统就会将对象销毁,回收内存。从而达到管理内存的目的。
如图,给appdelegate.m 关闭arc的情况下我们进行测试,首先我们看第一句 NSObject *ob = [[NSObject alloc]init]; 这句话干了什么事呢?先看右边,意思是在堆上开辟一块内存,用于存放 NSObjec的一个实例,再看左边,在栈上创建了一个指针,该指针存储的是堆上实例的内存地址,此时该块内存的referencecount = 1。 那NSObject *ob1 = ob; 又做了什么事呢? 这句话同样在栈上创建了一个指针存了堆上实例的内存地址,但是为什么referencecount没有增加呢?别急,我们看看下面这句话: NSObject *ob2 = [ob retain]; 这句话做了什么呢?同样在栈上创建了一个指针,存的是堆上的内存地址,不同的是有一个[ob retain]方法执行了,关键就在这个 retain方法,因为这个 方法的作用是 ob指针指向的内存块发消息说:喂,老兄,你的引用计数要加1啊,于是,内存块的引用计数就加了1。正因为ob1没有retain的过程,所以不会影响想其引用计数。
这里要明白一个根本问题,引用计数是内存块的属性,并不是指针的,所 以,指向同一块内存的指针的引用计数在同一时刻永远都该是一样的。
这个时候我们如果调用[ob release];或者[ob1 release];或者[ob2 release];起到的作用其实是一样的,他们都是告诉内存块:喂,老兄,你的引用计数要减一啊。如果我们不给ob或者ob1或者ob2置空的话,这三个指针还是存在的,只要内存块的引用计数不为0的话,我们调用[ob retainCount]或[ob1 retainCount]或[ob2 retainCount]的结果是一样的,一旦内存块引用计数为0,该对象在堆上的内存就会被系统释放,我们在调用 [*** retainCount]就会有野指针崩溃(指针指向的内存地址已经被释放了),所以要及时给指针置空。
到这里,基本上引用计数就理清了。如果有理解错的地方,欢迎各位同学指正。