weak:不会引起引用计数增加,并且在对象释放后会自动把指针置nil
Runtime维护了一个weak表(hasn散列表),用于存储指向某个对象的所有weak指针,该散列表的可以为所指对象的地址,value为指向当前对象所有weak修饰变量指针的数组
id obj =[ [NSObject alloc]init]; (OC中未指定修饰符的对象默认__strong修饰)
id __weak obj1 = obj (把当前赋值给__weak修饰的对象)
内部:runtime调用init_weak()函数,把赋值对象地址最为键值传入,把__weak修饰的变量的地址指针作为value传入,初始化__weak指针;
init_weak(&obj1, obj)
然后init_store()内部调用store_weak()函数为把上面的两个值传入,更新当前指针指向,创建新的弱引用表,调用过程简化版图如下
store_weak(&obj1, obj);
weak_entry_t结构体维护和存储指向一个对象的所有弱引用hash表
weak对象自动置nil原理:
当__weak修饰变量指针指向的对象引用计数为0时,系统会释放掉该对象,调用clearDeallocating 通过obj对象地址找到对应的弱引用表,并遍历array中的所有weak指针依次置nil后,删除当前地址所对应的entry(弱引用表)
模拟hash表中对象对应的弱引用表
假设有__weak 修饰的a、b、c、d、......指针变量都指向obj对象,那么对应的弱引用表如下
参考来自
iOS 底层解析weak的实现原理(包含weak对象的初始化,引用,释放的分析) - 简书
assign:一般修饰基本类型,不会引起引用计数增加,被修饰对象存储在栈区,系统自动管理内存的释放,不用开发者手动管理内存,但在assign修饰对象类型变量时,被修饰对象释放后,与weak的区别就在于当引用对象呗释放掉后,不会自动删除内存中的地址的内容并把指针变量置nil,会造成野指针,也就是说当前对象引用对象被释放掉后,再使用该对象时或再使用当前对象指向的内存地址时,会造成crash
栈区创建对象的特点就是对象随时会被销毁,再调用当前引用对象时就会造成崩溃
stong:强引用类型,修饰的对象会引起retainCount+1,默认情况下,所有实例变量和局部变量都是strong类型的;
strong类型变量指针会指向赋值对象,所以在对赋值对象做修改是,会影响被赋值对象的值
在修饰block时,strong与copy相似,都会把block放入栈区,由于MRC下生成的block都是在栈区,需要用copy方法把block拷贝到堆区,所以现在ARC下沿用了之前的传统,block也用copy修饰,其实用其他修饰符也可以,但是用weak/assign修饰block会出现提前释放的问题,造成崩溃;
copy&mutableCopy(NSString/NSMutableString/NSArray/NSMutableArray/NSDictionary/NSMutableDictionary):
首先我们要弄懂两个概念:
1、浅复制:不拷贝对象本身,只拷贝指向对象的指针(对象指针指向当前对象),一般‘=’赋值的对象都是shallow copy
2、深复制:在内存中开辟一块新的地址,把当前对象copy进去
接下来来说一下copy关键字的特点:赋值对象与被赋值对象相互独立,互不影响,各自修改操作也不会对对方有影响
copy:创建的是不可变副本(NSString,NSArray,NSDictionary)
1、当一个不可变得对象执行copy操作时,新对象的地址与旧对象完全相同,由于old对象不可变,所以copy的new对象也是不可修改的,两个对象永远不会影响到另一个对象,所以为了节省内存,不会产生新的对象(NSString,NSArray,NSDictionary) ———— shallow copy,执行copy操作都是这一道理;
2、浅拷贝因为不会产生新的对象,系统会对原对象进行retain
3、当一个可变对象(NSMutableString,NSMutableArray,NSMutableDictionary)执行copy操作时,new对象会生成一个不可变得对象,不可修改,所以会分配一块新的内存,———— deep copy
mutableCopy:创建的是可变副本(NSMutableString,NSMutableArray,NSMutableDictionary),无论是可变对象还是不可变对象执行mutableCopy操作,都会生成一个新的对象———— deep Copy
图片来源于网络weak、assign、strong、copy最大的区别就在于
1、是否增加引用计数
2、是否开辟新的内存
网友评论