一、copy
- 拷贝的目的:产生一个副本对象,跟源对象互不影响
- 修改了源对象,不会影响副本对象
- 修改了副本对象,不会影响源对象
iOS提供了2个拷贝方法
-
copy
不可变拷贝,产生不可变副本 -
mutableCopy
可变拷贝,产生可变副本
深拷贝和浅拷贝
-
深拷贝
内容拷贝,产生新的对象 -
浅拷贝
指针拷贝,没有产生新的对象
copy和mutableCopy 图解
1.
copy
都是不可变拷贝
,产生不可变副本
。mutableCopy
都是可变拷贝
,产生可变副本
。
2.除了不可变对象
的copy
是浅拷贝
,其他都是深拷贝
。
二、引用计数的存储
在64bit中,引用计数可以直接存储在优化过的isa
指针中,也可能存储在SideTable
类中
-
refcnts
是一个存放着对象引用计数的散列表
三、weak实现原理 - dealloc
当一个对象要释放时,会自动调用dealloc
,接下的调用轨迹是
1.dealloc 调用流程
1.首先调用 _objc_rootDealloc()
2.接下来调用 rootDealloc()
-
3.这时候会判断是否可以被释放,判断的依据主要有 5 个,判断是否有以上五种情况
- NONPointer_ISA
- weakly_reference
- has_assoc
- has_cxx_dtor
- has_sidetable_rc
-
4-1.如果有以上五中任意一种,将会调用 object_dispose()方法,做下一步的处理。
4-2.如果没有之前五种情况的任意一种,则可以执行释放操作,C 函数的 free()。
5.执行完毕。
2.object_dispose() 调用流程。
1.直接调用 objc_destructInstance()。
2.之后调用 C 函数的 free()。
3.objc_destructInstance() 调用流程
1.先判断 hasCxxDtor,如果有 C++ 的相关内容,要调用 object_cxxDestruct() ,销毁 C++ 相关的内容。
2.再判断 hasAssocitatedObjects,如果有的话,要调用 object_remove_associations(), 销毁关联对象的一系列操作。
3.然后调用 clearDeallocating()。
4.执行完毕。
4.clearDeallocating() 调用流程。
- 1.先执行 sideTable_clearDellocating()。
- 2.再执行 weak_clear_no_lock,在这一步骤中,会将指向该对象的弱引用指针置为 nil。
- 3.接下来执行 table.refcnts.eraser(),从引用计数表中擦除该对象的引用计数。
- 4.至此为止,Dealloc 的执行流程结束。
四、weak修饰的对象释放则自动被置为nil的实现原理:
Runtime维护了一个weak表,存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址数组(这个地址的值是所指对象的地址)。
weak 的实现原理可以概括一下三步:
1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak()函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。