「这是我参加2022初次更文应战的第28天,活动详情查看:2022初次更文应战」。
- 弱引证时干了什么,如下代码来看看
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *obj = [[NSObject alloc]init];
__weak NSObject *weakObj = obj;
}
return 0;
}
- 经过
clang
来看看cpp
代码
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_5c_vc7szrdj0xj63p71bn1fz8n80000gn_T_main_32a486_mi_0);
NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
__attribute__((objc_ownership(weak))) NSObject *weakObj = obj;
}
return 0;
}
- 可以看出是经过
objc_ownership
来完成,但是这样也没法追寻下去了
那么转换成.ll中间文件来看看
define i32 @main(i32 %0, i8** %1) #1 {
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca i8**, align 8
%6 = alloca %0*, align 8
%7 = alloca %0*, align 8
store i32 0, i32* %3, align 4
store i32 %0, i32* %4, align 4
store i8** %1, i8*** %5, align 8
%8 = call i8* @llvm.objc.autoreleasePoolPush() #2
notail call void (i8*, ...) @NSLog(i8* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to i8*))
%9 = load %struct._class_t*, %struct._class_t** @"OBJC_CLASSLIST_REFERENCES_$_", align 8
%10 = bitcast %struct._class_t* %9 to i8*
%11 = call i8* @objc_alloc_init(i8* %10)
%12 = bitcast i8* %11 to %0*
store %0* %12, %0** %6, align 8
%13 = load %0*, %0** %6, align 8
%14 = bitcast %0** %7 to i8**
%15 = bitcast %0* %13 to i8*
%16 = call i8* @llvm.objc.initWeak(i8** %14, i8* %15) #2
%17 = bitcast %0** %7 to i8**
call void @llvm.objc.destroyWeak(i8** %17) #2
%18 = bitcast %0** %6 to i8**
call void @llvm.objc.storeStrong(i8** %18, i8* null) #2
call void @llvm.objc.autoreleasePoolPop(i8* %8)
ret i32 0
}
- 可以看到
%16 = call i8* @llvm.objc.initWeak(i8** %14, i8* %15) #2
,是调用了objc
的initWeak
办法,那么就去objc
的源码里捋这个办法就行了,下面根本都是在源码里注释探究。
objc_initWeak
id
objc_initWeak(id *location, id newObj)
{
if (!newObj) {
*location = nil;
return nil;
}
return storeWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating>
(location, (objc_object*)newObj);
}
-
id *location
:注释上能看出,即__weak指针的地址,如文章最初比如中的weakObj
的地址 -
id newObj
:引证的目标,即文章最初比如中的obj
- 而后
return
了storeWeak
办法,这个便是核心完成了
storeWeak
enum HaveOld { DontHaveOld = false, DoHaveOld = true };
enum HaveNew { DontHaveNew = false, DoHaveNew = true };
enum CrashIfDeallocating {
DontCrashIfDeallocating = false, DoCrashIfDeallocating = true
};
template <HaveOld haveOld, HaveNew haveNew,
CrashIfDeallocating crashIfDeallocating>
static id
storeWeak(id *location, objc_object *newObj)
{
ASSERT(haveOld || haveNew);
if (!haveNew) ASSERT(newObj == nil);
Class previouslyInitializedClass = nil;
id oldObj;
SideTable *oldTable;
SideTable *newTable;
retry:
if (haveOld) {///假如weak ptr之前弱引证过一个obj,则将这个obj所对应的SideTable取出,赋值给oldTable
oldObj = *location;
oldTable = &SideTables()[oldObj];
} else {
oldTable = nil;/// 假如weak ptr之前没有弱引证过一个obj,则oldTable = nil
}
if (haveNew) {/// 假如weak ptr要weak引证一个新的obj,则将该obj对应的SideTable取出,赋值给newTable
newTable = &SideTables()[newObj];
} else {
newTable = nil;/// 假如weak ptr不需求引证一个新obj,则newTable = nil
}
/// 加锁
SideTable::lockTwo<haveOld, haveNew>(oldTable, newTable);
/// location 应该与 oldObj 保持一致,假如不同,阐明当时的 location 现已处理过 oldObj 可是又被其他线程所修改
if (haveOld && *location != oldObj) {
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
goto retry;
}
if (haveNew && newObj) {
Class cls = newObj->getIsa();
if (cls != previouslyInitializedClass &&
!((objc_class *)cls)->isInitialized())
{/// 假如cls还没有初始化,先初始化,再尝试设置weak
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
class_initialize(cls, (id)newObj);
previouslyInitializedClass = cls;
goto retry;/// 从头获取一遍newObj,这时的newObj应该现已初始化过了
}
}
// Clean up old value, if any.
if (haveOld) {
// 假如weak_ptr之前弱引证过别的目标oldObj,则调用weak_unregister_no_lock,在oldObj的weak_entry_t中移除该weak_ptr地址
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
}
// Assign new value, if any.
if (haveNew) {// 假如weak_ptr需求弱引证新的目标newObj
// 1. 调用weak_register_no_lock办法,将weak ptr的地址记录到newObj对应的weak_entry_t中
newObj = (objc_object *)
weak_register_no_lock(&newTable->weak_table, (id)newObj, location,
crashIfDeallocating);
// 2. 更新newObj的isa的weakly_referenced bit标志位
if (newObj && !newObj->isTaggedPointer()) {
newObj->setWeaklyReferenced_nolock();
}
// 3. *location 赋值,也便是将weak ptr直接指向了newObj。可以看到,这里并没有将newObj的引证计数+1
*location = (id)newObj;// 将weak ptr指向object
}
else {
// No new value. The storage is not changed.
}
// 解锁
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
return (id)newObj;// 返回newObj
}
-
storeWeak
办法接受5个参数,其中HaveOld haveOld, HaveNew haveNew, CrashIfDeallocating crashIfDeallocating
3个枚举别离传入的是false,true,true
,别离表明:weak ptr
之前是否现已指向了一个弱引证,weak ptr
是否需求指向一个新引证, 假如被弱引证的目标正在析构,此时再弱引证该目标,是否应该crash
。 - 结合上述代码注释应该大致能捋清楚
storeWeak
干了啥