欢迎加入伯乐在线 专栏作者。
前言
在上篇中,仔细分析了一下Block的实现原理以及__block捕获外部变量的原理。然而实际使用Block过程中,还是会遇到一些问题,比如Retain Circle的问题。
目录
- 1.Retain Circle的由来
- 2.weak、strong的实现原理
- 3.weakSelf、strongSelf的用途
- 4.@weakify、@strongify实现原理
一. Retain Circle的由来
循环引用的问题相信大家都很理解了,这里还是简单的提一下。
当A对象里面强引用了B对象,B对象又强引用了A对象,这样两者的retainCount值一直都无法为0,于是内存始终无法释放,导致内存泄露。所谓的内存泄露就是本应该释放的对象,在其生命周期结束之后依旧存在。
这是2个对象之间的,相应的,这种循环还能存在于3,4……个对象之间,只要相互形成环,就会导致Retain Cicle的问题。
当然也存在自身引用自身的,当一个对象内部的一个obj,强引用的自身,也会导致循环引用的问题出现。常见的就是block里面引用的问题。
二.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详细的文档,有兴趣的可以仔细研究一下文档里面的说明和例子,很有帮助。
以下的讲解,也会来自于上述文档中的函数说明。
1.__strong的实现原理
(1)对象持有自己
首先我们先来看看生成的对象持有自己的情况,利用alloc/new/copy/mutableCopy生成对象。
当我们声明了一个__strong对象
1
2
3
|
{
id
__strong
obj
=
[
[
NSObject
alloc
]
init
]
;
}
|
LLVM编译器会把上述代码转换成下面的样子
1
|
id
__attribute__
(
(
objc_ownership
(
strong
)
)
)
obj
=
(
(
NSObject
*
(
*
)
(
id
,
SEL
)
)
(
void
*
)
objc_msgSend
)
(
(
id
)
(
(
NSObject
*
(
*
)
(
id
,
SEL
)
)
(
void
*
)
objc_msgSend
)
(
(
id
)
objc_getClass
(
“NSObject”
)
,
sel_registerName
(
“alloc”
)
)
,
sel_registerName
(
“init”
)
)
;
|
相应的会调用
1
2
3
|
id
obj
=
objc_msgSend
(
NSObject
,
@selector
(
alloc
)
)
;
objc_msgSend
(
obj
,
selector
(
init
)
)
;
objc_release
(
obj
)
;
|
上述这些方法都好理解。在ARC有效的时候就会自动插入release代码,在作用域结束的时候自动释放。
(2)对象不持有自己
生成对象的时候不用alloc/new/copy/mutableCopy等方法。
1
2
3
|
{
id
__strong
obj
=
[
NSMutableArray
array
]
;
}
|
LLVM编译器会把上述代码转换成下面的样子
1
|
id
__attribute__
(
(
objc_ownership
(
strong
)
)
)
array
=
(
(
NSMutableArray
*
(
*
)
(
id
,
SEL
)
)
(
void
*
)
objc_msgSend
)
(
(
id
)
objc_getClass
(
“NSMutableArray”
)
,
sel_registerName
(
“array”
)
)
;
|
查看LLVM文档,其实是下述的过程
相应的会调用
1
2
3
|
id
obj
=
objc_msgSend
(
NSMutableArray
,
@selector
(
array
)
)
;
objc_retainAutoreleasedReturnValue
(
obj
)
;
objc_release
(
obj
)
;
|
与之前对象会持有自己的情况不同,这里多了一个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对象
1
2
3
|
{
id
__weak
obj
=
strongObj
;
}
|
假设这里的strongObj是一个已经声明好了的对象。
LLVM转换成对应的代码
1
|
id
__attribute__
(
(
objc_ownership
(
none
)
)
)
obj1
=
strongObj
;
|
相应的会调用
1
2
3
|
id
obj
;
objc_initWeak
(
&
obj
,
strongObj
)
;
objc_destoryWeak
(
&
obj
)
;
|
看看文档描述
id objc_initWeak(id *object, id value); Precondition: object is a valid pointer which has not been registered as a __weak object.
value is null or a pointer to a valid object. If value is a null pointer or the object to which it points has begun deallocation, object is zero-initialized. Otherwise, object is registered as a __weak object pointing to value
Equivalent to the following code: id objc_initWeak(id _object, id value) { _object = nil; return objc_storeWeak(object, value); }
Returns the value of object after the call. Does not need to be atomic with respect to calls to objc_storeWeak on object
objc_initWeak的实现其实是这样的
1
2
3
4
|
id
objc_initWeak
(
id
*object
,
id
value
)
{
*object
=
nil
;
return
objc_storeWeak
(
object
,
value
)
;
}
|
会把传入的object变成0或者nil,然后执行objc_storeWeak函数。
那么objc_destoryWeak函数是干什么的呢?
void objc_destroyWeak(id *object); Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak object.
object is unregistered as a weak object, if it ever was. The current value of object is left unspecified; otherwise, equivalent to the following code:
void objc_destroyWeak(id *object) { objc_storeWeak(object, nil); }
Does not need to be atomic with respect to calls to objc_storeWeak on object
objc_destoryWeak函数的实现
1
2
3
|
void
objc_destroyWeak
(
id
*object
)
{
objc_storeWeak
(
object
,
nil
)
;
}
|
也是会去调用objc_storeWeak函数。objc_initWeak和objc_destroyWeak函数都会去调用objc_storeWeak函数,唯一不同的是调用的入参不同,一个是value,一个是nil。
那么重点就都落在objc_storeWeak函数上了。
id objc_storeWeak(id *object, id value); Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak object. value is null or a pointer to a valid object.
If value is a null pointer or the object to which it points has begun deallocation, object is assigned null and unregistered as a weak object. Otherwise, object is registered as a weak object or has its registration updated to point to value
Returns the value of object after the call.
objc_storeWeak函数的用途就很明显了。由于weak表也是用Hash table实现的,所以objc_storeWeak函数就把第一个入参的变量地址注册到weak表中,然后根据第二个入参来决定是否移除。如果第二个参数为0,那么就把__weak变量从weak表中删除记录,并从引用计数表中删除对应的键值记录。
所以如果weak引用的原对象如果被释放了,那么对应的weak对象就会被指为nil。原来就是通过objc_storeWeak函数这些函数来实现的。
以上就是ARC中strong和weak的简单的实现原理,更加详细的还请大家去看看这一章开头提到的那个LLVM文档,里面说明的很详细。
三.weakSelf、strongSelf的用途
在提weakSelf、strongSelf之前,我们先引入一个Retain Cicle的例子。
假设自定义的一个student类
例子1:
1
2
3
4
5
6
|
#import
typedef
void
(
^
Study
)
(
)
;
@interface
Student
: NSObject
@property
(
copy
,
nonatomic
)
NSString
*name
;
@property
(
copy
,
nonatomic
)
Study
study
;
@end
|