1. 类扩展 VS 分类
1.1 类扩展(Extension
)
- 特殊的分类,也称作匿名分类
- 可以给类添加成员属性,但是为私有变量
- 可以给类添加方法,也是私有方法
1.2 分类(Category
)
- 专门用来给类添加新的方法
- 不能给类添加成员属性,添加后无法读取(可通过
Runtime
给分类添加属性) - 分类中使用
@property
定义变量,只会生成变量的getter/setter
方法的声明,不能生成方法的实现和下划线开头的成员变量
2. 类扩展的分析
2.1 cpp
文件探索
在main
函数中,写入LGPerson
的类扩展
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"Hello, World!");
}
return 0;
}
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *lgName;
- (void)say666;
@end
@interface LGPerson ()
@property (nonatomic, copy) NSString *ext_name;
- (void)ext_sayNB;
@end
@implementation LGPerson
- (void)say666{
NSLog(@"%@ - %s",self , __func__);
}
- (void)ext_sayNB{
NSLog(@"%@ - %s",self , __func__);
}
@end
- 类扩展的书写位置:声明之后,实现之前
生成cpp
文件
clang -rewrite-objc main.m -o main.cpp
对于类扩展中声明的属性,同样会生成下划线开头的成员变量
extern "C" unsigned long OBJC_IVAR_$_LGPerson$_lgName;
extern "C" unsigned long OBJC_IVAR_$_LGPerson$_ext_name;
struct LGPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_lgName;
NSString *_ext_name;
};
生成属性的getter/setter
方法
static NSString * _I_LGPerson_lgName(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_lgName)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
static void _I_LGPerson_setLgName_(LGPerson * self, SEL _cmd, NSString *lgName) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LGPerson, _lgName), (id)lgName, 0, 1); }
static NSString * _I_LGPerson_ext_name(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_ext_name)); }
static void _I_LGPerson_setExt_name_(LGPerson * self, SEL _cmd, NSString *ext_name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LGPerson, _ext_name), (id)ext_name, 0, 1); }
找到LGPerson
的成员变量列表
extern "C" unsigned long int OBJC_IVAR_$_LGPerson$_lgName __attribute__ ((used, section ("__DATA,__objc_ivar"))) = __OFFSETOFIVAR__(struct LGPerson, _lgName);
extern "C" unsigned long int OBJC_IVAR_$_LGPerson$_ext_name __attribute__ ((used, section ("__DATA,__objc_ivar"))) = __OFFSETOFIVAR__(struct LGPerson, _ext_name);
static struct /*_ivar_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count;
struct _ivar_t ivar_list[2];
} _OBJC_$_INSTANCE_VARIABLES_LGPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_ivar_t),
2,
{{(unsigned long int *)&OBJC_IVAR_$_LGPerson$_lgName, "_lgName", "@\"NSString\"", 3, 8},
{(unsigned long int *)&OBJC_IVAR_$_LGPerson$_ext_name, "_ext_name", "@\"NSString\"", 3, 8}}
};
找到LGPerson
的方法列表
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[10];
} _OBJC_$_INSTANCE_METHODS_LGPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
10,
{{(struct objc_selector *)"say666", "v16@0:8", (void *)_I_LGPerson_say666},
{(struct objc_selector *)"ext_sayNB", "v16@0:8", (void *)_I_LGPerson_ext_sayNB},
{(struct objc_selector *)"lgName", "@16@0:8", (void *)_I_LGPerson_lgName},
{(struct objc_selector *)"setLgName:", "v24@0:8@16", (void *)_I_LGPerson_setLgName_},
{(struct objc_selector *)"ext_name", "@16@0:8", (void *)_I_LGPerson_ext_name},
{(struct objc_selector *)"setExt_name:", "v24@0:8@16", (void *)_I_LGPerson_setExt_name_},
{(struct objc_selector *)"lgName", "@16@0:8", (void *)_I_LGPerson_lgName},
{(struct objc_selector *)"setLgName:", "v24@0:8@16", (void *)_I_LGPerson_setLgName_},
{(struct objc_selector *)"ext_name", "@16@0:8", (void *)_I_LGPerson_ext_name},
{(struct objc_selector *)"setExt_name:", "v24@0:8@16", (void *)_I_LGPerson_setExt_name_}}
};
类扩展和分类的明显区别,不会生成额外的结构体存储类扩展的信息、类扩展中的属性和方法,和LGPerson
主类的属性和方法融为一体
2.2 objc
源码探索
在项目中,创建LGPerson+Ext.h
类扩展
#import "LGPerson.h"
@interface LGPerson ()
@property (nonatomic, copy) NSString *ext_name;
- (void)ext_say666;
@end
在LGPerson
中,实现ext_say666
方法
#import "LGPerson.h"
#import "LGPerson+Ext.h"
@implementation LGPerson
+ (void)load{
NSLog(@"%@ - %s",self , __func__);
}
- (void)say1{
NSLog(@"%@ : %s",self,__func__);
}
- (void)ext_say666{
NSLog(@"%@ : %s",self,__func__);
}
@end
主类执行流程没有任何变化,在realizeClassWithoutSwift
函数中,读取ro
方法列表中,同时也包含类扩展中声明的方法
所以类扩展并不会影响主类的加载流程,在编译时,类扩展中的属性和方法和主类融为一体
创建的类扩展只有·h
文件,所以只做声明,实现需要依赖于当前的主类
3. 关联对象
分类中,不能直接使用属性的getter/setter
方法,只能使用关联对象的方式实现成员变量的效果
关联对象的两个核心方法,值的存储和读取
值的存储
void
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
object
:被关联者key
:标识符value
:值policy
:关联策略
值的读取
void objc_removeAssociatedObjects(id object)
object
:被关联者key
:标识符
关联策略
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
* The association is made atomically. */
};
nonatomic
、atomic
、assign
、retain
、copy
等修饰
3.1 objc_setAssociatedObject
& objc_getAssociatedObject
void
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
{
_object_set_associative_reference(object, key, value, policy);
}
id
objc_getAssociatedObject(id object, const void *key)
{
return _object_get_associative_reference(object, key);
}
objc_setAssociatedObject
和objc_getAssociatedObject
函数为中间层层代码,目的是对业务层进行隔离。因为底层API
根据不同版本会发生变化,但中间层代码是保持不变的,所以开发者不用担心因底层API
变化导致程序的修改
3.2 _object_set_associative_reference
void
_object_set_associative_reference(id object, const void *key, id value, uintptr_t policy)
{
// This code used to work when nil was passed for object and key. Some code
// probably relies on that to not crash. Check and handle it explicitly.
// rdar://problem/44094390
if (!object && !value) return;
if (object->getIsa()->forbidsAssociatedObjects())
_objc_fatal("objc_setAssociatedObject called on instance (%p) of class %s which does not allow associated objects", object, object_getClassName(object));
//将不同类型的object,保存成统一结构
DisguisedPtr<objc_object> disguised{(objc_object *)object};
//将关联策略和值,以面向对象的方式进行存储
ObjcAssociation association{policy, value};
// retain the new value (if any) outside the lock.
//根据不同的关联策略进行处理
association.acquireValue();
bool isFirstAssociation = false;
{
//调用构造函数,加锁。函数作用域结束AssociationsManager释放,调用析构函数,解锁
AssociationsManager manager;
//获取唯⼀的全局静态哈希Map
//验证方式:get函数中调用_mapStorage.get(),而_mapStorage为static修饰
AssociationsHashMap &associations(manager.get());
if (value) {
//被关联者和ObjectAssociationMap进行关联
auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{});
if (refs_result.second) {
/* it's the first association we make */
//首次关联,打标记
isFirstAssociation = true;
}
/* establish or replace the association */
//建立或替换关联
auto &refs = refs_result.first->second;
auto result = refs.try_emplace(key, std::move(association));
if (!result.second) {
//如果存在旧值,替换为新值
association.swap(result.first->second);
}
} else {
//value不存在,移除关联
//通过关联对象寻址Iterator
auto refs_it = associations.find(disguised);
if (refs_it != associations.end()) {
//获取ObjectAssociationMap
auto &refs = refs_it->second;
//通过key寻址Iterator
auto it = refs.find(key);
if (it != refs.end()) {
//替换ObjcAssociation,新值替换旧值
association.swap(it->second);
//移除旧值
refs.erase(it);
if (refs.size() == 0) {
//如果关联对象关联的Iterator为空,直接移除
associations.erase(refs_it);
}
}
}
}
}
// Call setHasAssociatedObjects outside the lock, since this
// will call the object's _noteAssociatedObjects method if it
// has one, and this may trigger +initialize which might do
// arbitrary stuff, including setting more associated objects.
//在nonpointerIsa中标记
if (isFirstAssociation)
object->setHasAssociatedObjects();
// release the old value (outside of the lock).
//释放旧值
association.releaseHeldValue();
}
【步骤一】
将不同类型的
object
,保存成统一的DisguisedPtr<objc_object>
结构将关联策略和值,以面向对象的方式进行存储
ObjcAssociation
类中根据不同的关联策略进行处理
【步骤二】
调用构造函数,加锁。函数作用域结束
AssociationsManager
释放,调用析构函数,解锁AssociationsHashMap
为单例,在内存中只有一份
【步骤三】
如果
value
存在,进行关联调用
AssociationsHashMap
的try_emplace
函数,将object
和ObjectAssociationMap
关联返回结果
refs_result
,如果是首次关联,打标记在
refs_result
中找到object
关联的Bucket
调用
Bucket
的try_emplace
函数,将key
关联ObjcAssociation
类如果存在旧值,替换为新值
如果传入的
value
不存在,移除关联通过关联对象寻址
Iterator
获取
ObjectAssociationMap
替换
ObjcAssociation
,新值替换旧值移除旧值
如果关联对象关联的
Iterator
为空,直接移除
【步骤四】
在
nonpointerIsa
中标记,当对象销毁时,关联对象也要跟随销毁释放旧值
3.2.1 AssociationsHashMap
单例
class AssociationsManager {
using Storage = ExplicitInitDenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap>;
static Storage _mapStorage;
public:
AssociationsManager() { AssociationsManagerLock.lock(); }
~AssociationsManager() { AssociationsManagerLock.unlock(); }
AssociationsHashMap &get() {
return _mapStorage.get();
}
static void init() {
_mapStorage.init();
}
};
AssociationsManager
的get
函数,调用_mapStorage
的get
函数_mapStorage
:使用static
修饰,全局静态对象AssociationsManager()
:构造函数,加锁~AssociationsManager()
:析构函数,解锁- 加锁、解锁操作,保证对象的安全性,防止冲突
验证AssociationsManager
和AssociationsHashMap
的单例模式,将AssociationsManager
中的构造函数和析构函数注释,避免锁递归报错
void test(){
AssociationsManager manager1;
AssociationsHashMap &associations1(manager1.get());
printf("AssociationsManager1:%p\n", &manager1);
printf("AssociationsHashMap1:%p\n", &associations1);
AssociationsManager manager2;
AssociationsHashMap &associations2(manager2.get());
printf("AssociationsManager2:%p\n", &manager2);
printf("AssociationsHashMap2:%p\n", &associations2);
AssociationsManager manager3;
AssociationsHashMap &associations3(manager3.get());
printf("AssociationsManager3:%p\n", &manager3);
printf("AssociationsHashMap3:%p\n", &associations3);
}
-------------------------
AssociationsManager1:0x7ffeefbff258
AssociationsHashMap1:0x100370188
AssociationsManager2:0x7ffeefbff248
AssociationsHashMap2:0x100370188
AssociationsManager3:0x7ffeefbff238
AssociationsHashMap3:0x100370188
AssociationsManager
不是单例对象,每次创建的内存地址都不一样AssociationsHashMap
为单例对象,内存地址一致
3.2.2 AssociationsManager
的初始化
AssociationsManager
的init
函数使用static
修饰,表示类对象函数,找到它的初始化时机
_objc_associations_init
函数
void
_objc_associations_init()
{
AssociationsManager::init();
}
arr_init
函数
void arr_init(void)
{
AutoreleasePoolPage::init();
SideTablesMap.init();
_objc_associations_init();
}
map_images_nolock
函数
void
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[])
{
...
if (firstTime) {
sel_init(selrefCount);
arr_init();
...
}
...
}
AssociationsManager
初始化流程:map_images
→map_images_nolock
→arr_init
→_objc_associations_init
也就是在此时,系统创建了AssociationsHashMap
关联对象表。和它一起被创建的全局系统表,还有AutoreleasePoolPage
自动释放池,以及SideTablesMap
散列表
SideTablesMap
散列表中包含两张子表,分别是RefcountMap
引用计数表,还有weak_table_t
弱引用表
3.2.3 AssociationsHashMap
结构
AssociationsHashMap
为双层HashMap
结构
typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMap;
DisguisedPtr<objc_object>
为被关联者,它所对应的值还是一张HashMap
ObjectAssociationMap
为HashMap
结构
typedef DenseMap<const void *, ObjcAssociation> ObjectAssociationMap;
const void *
为标识号,它所对应的值为ObjcAssociation
类
ObjcAssociation
为class
结构
class ObjcAssociation {
uintptr_t _policy;
id _value;
...
}
_policy
:关联策略_value
:值
3.2.4 try_emplace
函数
template <typename... Ts>
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
BucketT *TheBucket;
//查看Bucket在map中是否存在,存在将Bucket返回
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), true),
false); // Already in map.
// Otherwise, insert the new element.
//不存在,插入Bucket并返回
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), true),
true);
}
- 通过
std::make_pair
生成相应的键值对 LookupBucketFor
函数,查看Bucket
在map
中是否存在,存在将Bucket
返回- 不存在,调用
InsertIntoBucket
函数,插入Bucket
并返回
3.2.5 LookupBucketFor
函数
- 两个函数的区别在于
Bucket
参数的const
修饰 - 作用:为
value
查找适当的Bucket
,并将其返回
LookupBucketFor
函数一,Bucket
使用const
修饰
template<typename LookupKeyT>
bool LookupBucketFor(const LookupKeyT &Val,
const BucketT *&FoundBucket) const {
const BucketT *BucketsPtr = getBuckets();
const unsigned NumBuckets = getNumBuckets();
if (NumBuckets == 0) {
FoundBucket = nullptr;
return false;
}
// FoundTombstone - Keep track of whether we find a tombstone while probing.
const BucketT *FoundTombstone = nullptr;
const KeyT EmptyKey = getEmptyKey();
const KeyT TombstoneKey = getTombstoneKey();
assert(!KeyInfoT::isEqual(Val, EmptyKey) &&
!KeyInfoT::isEqual(Val, TombstoneKey) &&
"Empty/Tombstone value shouldn't be inserted into map!");
//哈希函数,计算下标
unsigned BucketNo = getHashValue(Val) & (NumBuckets-1);
unsigned ProbeAmt = 1;
while (true) {
//内存平移,获取Bucket
const BucketT *ThisBucket = BucketsPtr + BucketNo;
// Found Val's bucket? If so, return it.
//找到Bucket,直接返回
if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
FoundBucket = ThisBucket;
return true;
}
// If we found an empty bucket, the key doesn't exist in the set.
// Insert it and return the default value.
//Bucket为空,返回默认值
if (LLVM_LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
// If we've already seen a tombstone while probing, fill it in instead
// of the empty bucket we eventually probed to.
FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
return false;
}
// If this is a tombstone, remember it. If Val ends up not in the map, we
// prefer to return it than something that would require more probing.
// Ditto for zero values.
//哈希冲突,再次哈希
if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) &&
!FoundTombstone)
FoundTombstone = ThisBucket; // Remember the first tombstone found.
if (ValueInfoT::isPurgeable(ThisBucket->getSecond()) && !FoundTombstone)
FoundTombstone = ThisBucket;
// Otherwise, it's a hash collision or a tombstone, continue quadratic
// probing.
if (ProbeAmt > NumBuckets) {
FatalCorruptHashTables(BucketsPtr, NumBuckets);
}
BucketNo += ProbeAmt++;
BucketNo &= (NumBuckets-1);
}
}
- 哈希函数,计算下标
- 内存平移,获取
Bucket
- 找到
Bucket
,直接返回 Bucket
为空,返回默认值- 哈希冲突,再次哈希
LookupBucketFor
函数二,Bucket
未使用const
修饰
template <typename LookupKeyT>
bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) {
//创建空Bucket
const BucketT *ConstFoundBucket;
//调用LookupBucketFor函数一
bool Result = const_cast<const DenseMapBase *>(this)
->LookupBucketFor(Val, ConstFoundBucket);
//将ConstFoundBucket赋值FoundBucket
FoundBucket = const_cast<BucketT *>(ConstFoundBucket);
//返回结果,是否查找到Bucket
return Result;
}
- 创建空
Bucket
- 调用
LookupBucketFor
函数一 - 将
ConstFoundBucket
赋值FoundBucket
- 返回结果,是否查找到
Bucket
3.2.6 InsertIntoBucket
函数
template <typename KeyArg, typename... ValueArgs>
BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
ValueArgs &&... Values) {
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
TheBucket->getFirst() = std::forward<KeyArg>(Key);
::new (&TheBucket->getSecond()) ValueT(std::forward<ValueArgs>(Values)...);
return TheBucket;
}
- 调用
InsertIntoBucketImpl
函数
InsertIntoBucketImpl
函数
template <typename LookupKeyT>
BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup,
BucketT *TheBucket) {
// If the load of the hash table is more than 3/4, or if fewer than 1/8 of
// the buckets are empty (meaning that many are filled with tombstones),
// grow the table.
//
// The later case is tricky. For example, if we had one empty bucket with
// tons of tombstones, failing lookups (e.g. for insertion) would have to
// probe almost the entire table until it found the empty bucket. If the
// table completely filled with tombstones, no lookup would ever succeed,
// causing infinite loops in lookup.
unsigned NewNumEntries = getNumEntries() + 1;
unsigned NumBuckets = getNumBuckets();
if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
this->grow(NumBuckets * 2);
LookupBucketFor(Lookup, TheBucket);
NumBuckets = getNumBuckets();
} else if (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <=
NumBuckets/8)) {
this->grow(NumBuckets);
LookupBucketFor(Lookup, TheBucket);
}
ASSERT(TheBucket);
// Only update the state after we've grown our bucket space appropriately
// so that when growing buckets we have self-consistent entry count.
// If we are writing over a tombstone or zero value, remember this.
if (KeyInfoT::isEqual(TheBucket->getFirst(), getEmptyKey())) {
// Replacing an empty bucket.
incrementNumEntries();
} else if (KeyInfoT::isEqual(TheBucket->getFirst(), getTombstoneKey())) {
// Replacing a tombstone.
incrementNumEntries();
decrementNumTombstones();
} else {
// we should be purging a zero. No accounting changes.
ASSERT(ValueInfoT::isPurgeable(TheBucket->getSecond()));
TheBucket->getSecond().~ValueT();
}
return TheBucket;
}
- 如果哈希表的负载大于
3/4
,两倍扩容
3.3 _object_get_associative_reference
id
_object_get_associative_reference(id object, const void *key)
{
ObjcAssociation association{};
{
//调用构造函数,加锁。函数作用域结束AssociationsManager释放,调用析构函数,解锁
AssociationsManager manager;
//获取唯⼀的全局静态哈希Map
AssociationsHashMap &associations(manager.get());
//通过关联对象寻址Iterator
AssociationsHashMap::iterator i = associations.find((objc_object *)object);
if (i != associations.end()) {
//获取ObjectAssociationMap
ObjectAssociationMap &refs = i->second;
//通过key寻址Iterator
ObjectAssociationMap::iterator j = refs.find(key);
if (j != refs.end()) {
//获取ObjcAssociation
association = j->second;
//保留返回值
association.retainReturnedValue();
}
}
}
//生成自动返回值
return association.autoreleaseReturnedValue();
}
【第一步】
调用构造函数,加锁。函数作用域结束
AssociationsManager
释放,调用析构函数,解锁AssociationsHashMap
为单例,在内存中只有一份
【第二步】
通过关联对象寻址
Iterator
获取
ObjectAssociationMap
【第三步】
通过
key
寻址Iterator
获取
ObjcAssociation
保留返回值
【第四步】
- 生成自动返回值
3.4 关联对象的销毁
关联对象的销毁,依赖于被关联对象的生命周期。当被关联对象被销毁时,它的关联对象会自动销毁
对象销毁流程:
C++
函数释放 :objc_cxxDestruct
- 关联对象销毁:
_object_remove_assocations
- 弱引用销毁:
weak_clear_no_lock
- 清空引用计数:
table.refcnts.erase
- 销毁对象:
free
3.4.1 dealloc
- (void)dealloc {
_objc_rootDealloc(self);
}
3.4.2 _objc_rootDealloc
void
_objc_rootDealloc(id obj)
{
ASSERT(obj);
obj->rootDealloc();
}
3.4.3 rootDealloc
inline void
objc_object::rootDealloc()
{
if (isTaggedPointer()) return; // fixme necessary?
if (fastpath(isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
#if ISA_HAS_CXX_DTOR_BIT
!isa.has_cxx_dtor &&
#else
!isa.getClass(false)->hasCxxDtor() &&
#endif
!isa.has_sidetable_rc))
{
assert(!sidetable_present());
free(this);
}
else {
object_dispose((id)this);
}
}
- 判断
C++
析构函数的调用、关联对象的销毁、弱引用的销毁、引用计数是否清空,全部符合条件,调用free
函数销毁对象 - 否则,调用
object_dispose
函数,继续销毁流程
3.4.4 object_dispose
id
object_dispose(id obj)
{
if (!obj) return nil;
objc_destructInstance(obj);
free(obj);
return nil;
}
3.4.5 objc_destructInstance
void *objc_destructInstance(id obj)
{
if (obj) {
// Read all of the flags at once for performance.
bool cxx = obj->hasCxxDtor();
bool assoc = obj->hasAssociatedObjects();
// This order is important.
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj, /*deallocating*/true);
obj->clearDeallocating();
}
return obj;
}
object_cxxDestruct
:调用C++
的析构函数_object_remove_assocations
:关联对象销毁clearDeallocating
,弱引用销毁、清空引用计数
3.4.6 _object_remove_assocations
void
_object_remove_assocations(id object, bool deallocating)
{
ObjectAssociationMap refs{};
{
//调用构造函数,加锁。函数作用域结束AssociationsManager释放,调用析构函数,解锁
AssociationsManager manager;
//获取唯⼀的全局静态哈希Map
AssociationsHashMap &associations(manager.get());
//通过关联对象寻址Iterator
AssociationsHashMap::iterator i = associations.find((objc_object *)object);
if (i != associations.end()) {
//替换
refs.swap(i->second);
// If we are not deallocating, then SYSTEM_OBJECT associations are preserved.
bool didReInsert = false;
if (!deallocating) {
for (auto &ref: refs) {
if (ref.second.policy() & OBJC_ASSOCIATION_SYSTEM_OBJECT) {
i->second.insert(ref);
didReInsert = true;
}
}
}
//移除Iterator
if (!didReInsert)
associations.erase(i);
}
}
// Associations to be released after the normal ones.
SmallVector<ObjcAssociation *, 4> laterRefs;
// release everything (outside of the lock).
for (auto &i: refs) {
if (i.second.policy() & OBJC_ASSOCIATION_SYSTEM_OBJECT) {
// If we are not deallocating, then RELEASE_LATER associations don't get released.
if (deallocating)
laterRefs.append(&i.second);
} else {
i.second.releaseHeldValue();
}
}
//循环销毁
for (auto *later: laterRefs) {
later->releaseHeldValue();
}
}
关联对象销毁流程:dealloc
→_objc_rootDealloc
→rootDealloc
→object_dispose
→objc_destructInstance
→_object_remove_assocations
3.4.7 clearDeallocating
inline void
objc_object::clearDeallocating()
{
if (slowpath(!isa.nonpointer)) {
// Slow path for raw pointer isa.
sidetable_clearDeallocating();
}
else if (slowpath(isa.weakly_referenced || isa.has_sidetable_rc)) {
// Slow path for non-pointer isa with weak refs and/or side table data.
clearDeallocating_slow();
}
assert(!sidetable_present());
}
3.4.8 clearDeallocating_slow
NEVER_INLINE void
objc_object::clearDeallocating_slow()
{
ASSERT(isa.nonpointer && (isa.weakly_referenced || isa.has_sidetable_rc));
SideTable& table = SideTables()[this];
table.lock();
if (isa.weakly_referenced) {
weak_clear_no_lock(&table.weak_table, (id)this);
}
if (isa.has_sidetable_rc) {
table.refcnts.erase(this);
}
table.unlock();
}
weak_clear_no_lock
:弱引用销毁table.refcnts.erase
:清空引用计数
总结
类扩展 VS 分类:
- 类扩展(
Extension
)- 特殊的分类,也称作匿名分类
- 可以给类添加成员属性,但是为私有变量
- 可以给类添加方法,也是私有方法
- 分类(
Category
)- 专门用来给类添加新的方法
- 不能给类添加成员属性,添加后无法读取(可通过
Runtime
给分类添加属性) - 分类中使用
@property
定义变量,只会生成变量的getter/setter
方法的声明,不能生成方法的实现和下划线开头的成员变量
类扩展的分析:
- 所以类扩展并不会影响主类的加载流程,在编译时,类扩展中的属性和方法和主类融为一体
- 创建的类扩展只有
·h
文件,所以只做声明,实现需要依赖于当前的主类
关联对象:
- 分类中,不能直接使用属性的
getter/setter
方法,只能使用关联对象的方式实现成员变量的效果 objc_setAssociatedObject
object
:被关联者key
:标识符value
:值policy
:关联策略
objc_removeAssociatedObjects
object
:被关联者key
:标识符
- 关联策略:
nonatomic
、atomic
、assign
、retain
、copy
等修饰
objc_setAssociatedObject
& objc_getAssociatedObject
:
- 函数为中间层层代码,目的是对业务层进行隔离。因为底层
API
根据不同版本会发生变化,但中间层代码是保持不变的,所以开发者不用担心因底层API
变化导致程序的修改
_object_set_associative_reference
:
【步骤一】
- 将不同类型的
object
,保存成统一的DisguisedPtr<objc_object>
结构 - 将关联策略和值,以面向对象的方式进行存储
ObjcAssociation
类中 - 根据不同的关联策略进行处理
【步骤二】
- 调用构造函数,加锁。函数作用域结束
AssociationsManager
释放,调用析构函数,解锁 AssociationsHashMap
为单例,在内存中只有一份
【步骤三】
- 如果
value
存在,进行关联- 调用
AssociationsHashMap
的try_emplace
函数,将object
和ObjectAssociationMap
关联 - 返回结果
refs_result
,如果是首次关联,打标记 - 在
refs_result
中找到object
关联的Bucket
- 调用
Bucket
的try_emplace
函数,将key
关联ObjcAssociation
类 - 如果存在旧值,替换为新值
- 调用
- 如果传入的
value
不存在,移除关联- 通过关联对象寻址
Iterator
- 获取
ObjectAssociationMap
- 替换
ObjcAssociation
,新值替换旧值 - 移除旧值
- 如果关联对象关联的
Iterator
为空,直接移除
- 通过关联对象寻址
【步骤四】
- 在
nonpointerIsa
中标记,当对象销毁时,关联对象也要跟随销毁 - 释放旧值
_object_get_associative_reference
:
【第一步】
- 调用构造函数,加锁。函数作用域结束
AssociationsManager
释放,调用析构函数,解锁 AssociationsHashMap
为单例,在内存中只有一份
【第二步】
- 通过关联对象寻址
Iterator
- 获取
ObjectAssociationMap
【第三步】
- 通过
key
寻址Iterator
- 获取
ObjcAssociation
- 保留返回值
【第四步】
- 生成自动返回值
关联对象的销毁:
- 关联对象的销毁,依赖于被关联对象的生命周期。当被关联对象被销毁时,它的关联对象会自动销毁
- 对象销毁流程:
C++
函数释放 :objc_cxxDestruct
- 关联对象销毁:
_object_remove_assocations
- 弱引用销毁:
weak_clear_no_lock
- 清空引用计数:
table.refcnts.erase
- 销毁对象:
free
- 销毁流程:
dealloc
→_objc_rootDealloc
→rootDealloc
→object_dispose
→objc_destructInstance
→_object_remove_assocations
AssociationsHashMap
:
- 单例,使用
static
修饰,全局静态对象 - 双层
HashMap
结构
AssociationsManager
:
- 可创建多份,并为唯一
AssociationsManager()
:构造函数,加锁~AssociationsManager()
:析构函数,解锁- 加锁、解锁操作,保证对象的安全性,防止冲突
AssociationsManager
的初始化:
- 初始化流程:
map_images
→map_images_nolock
→arr_init
→_objc_associations_init
- 在
map_images
时,系统创建AssociationsHashMap
关联对象表。和它一起被创建的全局系统表,还有AutoreleasePoolPage
自动释放池,以及SideTablesMap
散列表 SideTablesMap
散列表中包含两张子表,分别是RefcountMap
引用计数表,还有weak_table_t
弱引用表