深入研究Block用weakSelf、strongSelf、@weakify、@strongify解决循环引用

500 查看

111194012-d3d8244be4e6059f

前言

在上篇中,仔细分析了一下Block的实现原理以及__block捕获外部变量的原理。然而实际使用Block过程中,还是会遇到一些问题,比如Retain Circle的问题。

目录

  • 1.Retain Circle的由来
  • 2.weak、strong的实现原理
  • 3.weakSelf、strongSelf的用途
  • 4.@weakify、@strongify实现原理

一. Retain Circle的由来

121194012-2eb65c853e014ed3

循环引用的问题相信大家都很理解了,这里还是简单的提一下。

当A对象里面强引用了B对象,B对象又强引用了A对象,这样两者的retainCount值一直都无法为0,于是内存始终无法释放,导致内存泄露。所谓的内存泄露就是本应该释放的对象,在其生命周期结束之后依旧存在。

131194012-aeffe9c77bf9ef5c

这是2个对象之间的,相应的,这种循环还能存在于3,4……个对象之间,只要相互形成环,就会导致Retain Cicle的问题。

当然也存在自身引用自身的,当一个对象内部的一个obj,强引用的自身,也会导致循环引用的问题出现。常见的就是block里面引用的问题。

141194012-e6f47d76a23b40c6

二.weak、strong的实现原理

在ARC环境下,id类型和对象类型和C语言其他类型不同,类型前必须加上所有权的修饰符。

所有权修饰符总共有4种:

1.strong修饰符 2.weak修饰符 3.unsafe_unretained修饰符 4.autoreleasing修饰符

一般我们如果不写,默认的修饰符是__strong。

要想弄清楚strong,weak的实现原理,我们就需要研究研究clang(LLVM编译器)和objc4 Objective-C runtime库了。

关于clang有一份关于ARC详细的文档,有兴趣的可以仔细研究一下文档里面的说明和例子,很有帮助。

以下的讲解,也会来自于上述文档中的函数说明。

151194012-8ba2276f15bbfd49
1.__strong的实现原理
(1)对象持有自己

首先我们先来看看生成的对象持有自己的情况,利用alloc/new/copy/mutableCopy生成对象。

当我们声明了一个__strong对象

LLVM编译器会把上述代码转换成下面的样子

相应的会调用

上述这些方法都好理解。在ARC有效的时候就会自动插入release代码,在作用域结束的时候自动释放。

(2)对象不持有自己

生成对象的时候不用alloc/new/copy/mutableCopy等方法。

LLVM编译器会把上述代码转换成下面的样子

查看LLVM文档,其实是下述的过程

相应的会调用

与之前对象会持有自己的情况不同,这里多了一个objc_retainAutoreleasedReturnValue函数。

这里有3个函数需要说明:

1.id objc_retainAutoreleaseReturnValue(id value)

id objc_retainAutoreleaseReturnValue(id value); Precondition: value is null or a pointer to a valid object.

If value is null, this call has no effect. Otherwise, it performs a retain operation followed by the operation described in objc_autoreleaseReturnValue.

Equivalent to the following code: id objc_retainAutoreleaseReturnValue(id value) { return objc_autoreleaseReturnValue(objc_retain(value)); }

Always returns value

2.id objc_retainAutoreleasedReturnValue(id value)

id objc_retainAutoreleasedReturnValue(id value); Precondition: value is null or a pointer to a valid object.

If value is null, this call has no effect. Otherwise, it attempts to accept a hand off of a retain count from a call to objc_autoreleaseReturnValue on value in a recently-called function or something it calls. If that fails, it performs a retain operation exactly like objc_retain.

Always returns value

3.id objc_autoreleaseReturnValue(id value)

id objc_autoreleaseReturnValue(id value); Precondition: value is null or a pointer to a valid object.

If value is null, this call has no effect. Otherwise, it makes a best effort to hand off ownership of a retain count on the object to a call toobjc_retainAutoreleasedReturnValue for the same object in an enclosing call frame. If this is not possible, the object is autoreleased as above.

Always returns value

这3个函数其实都是在描述一件事情。 it makes a best effort to hand off ownership of a retain count on the object to a call to objc_retainAutoreleasedReturnValue for the same object in an enclosing call frame。

这属于LLVM编译器的一个优化。objc_retainAutoreleasedReturnValue函数是用于自己持有(retain)对象的函数,它持有的对象应为返回注册在autoreleasepool中对象的方法或者是函数的返回值。

在ARC中原本对象生成之后是要注册到autoreleasepool中,但是调用了objc_autoreleasedReturnValue 之后,紧接着调用了 objc_retainAutoreleasedReturnValue,objc_autoreleasedReturnValue函数会去检查该函数方法或者函数调用方的执行命令列表,如果里面有objc_retainAutoreleasedReturnValue()方法,那么该对象就直接返回给方法或者函数的调用方。达到了即使对象不注册到autoreleasepool中,也可以返回拿到相应的对象。

2.__weak的实现原理

声明一个__weak对象