
(lldb) memory read person
0x600002e264f0: d0 e7 de 03 01 00 00 00 61 62 00 00 14 00 00 00 ........ab......
0x600002e26500: 38 c0 de 03 01 00 00 00 58 c0 de 03 01 00 00 00 8.......X.......
(lldb) x/6gx person (x:打印内存格式 4: 打印4段 g: 打印 x: 16进制打印16位 w:打印16进制的8位)
0x600002e264f0: 0x0000000103dee7d0 0x0000001400006261
0x600002e26500: 0x0000000103dec038 0x0000000103dec058
0x600002e26510: 0x0000000000000000 0x0000000000000000\
OC对象的本质
在一个内中添加一个私有类,在main.m文件中添加一个LGPerson类
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation LGPerson
@end
使用clang将main.m编译为main.cpp
cd进入工程目录下
clang -rewrite-objc main.m -o main.cpp
会看到在main.m文件同目下生成一个main.cpp文件,打开main.cpp文件,直接查找LGPerosn相关的
//我们可以发现LGPerson在底层其实就是struct结构体
extern "C" unsigned long OBJC_IVAR_$_LGPerson$_name;
struct LGPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS; // isa
NSString *_name;
};
// @property (nonatomic, copy) NSString *name;
/* @end */
// @implementation LGPerson
//get方法
static NSString * _I_LGPerson_name(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_name)); }
// 所有的set方法都会通过objc_setProperty去实现
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
//set方法
static void _I_LGPerson_setName_(LGPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LGPerson, _name), (id)name, 0, 1); }
// @end
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_qh_pdfhk2010yz_2g4kgb84zmmr0000gn_T_main_8452c9_mi_0);
}
return 0;
}
objc_setProperty相当于一个通用接口,工厂模式,通用一个模板方法去给属性赋值
objc_setProperty实现

alloc - > _objc_rootAlloc -> callAlloc -> ISA()
1.alloc
+ (id)alloc {
return _objc_rootAlloc(self);
}
2._objc_rootAlloc
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
3.callAlloc
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
if (slowpath(checkNil && !cls)) return nil;
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
return _objc_rootAllocWithZone(cls, nil);
}
#endif
// No shortcuts available.
if (allocWithZone) {
return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}
4. ISA
inline Class
objc_object::ISA()
{
ASSERT(!isTaggedPointer());
#if SUPPORT_INDEXED_ISA
if (isa.nonpointer) {
uintptr_t slot = isa.indexcls;
return classForIndex((unsigned)slot);
}
return (Class)isa.bits;
#else
return (Class)(isa.bits & ISA_MASK);
#endif
}
5. isa_t
union isa_t { //联合体
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
由此可见 isa就是class类型的指针,ISA里面是一个联合体,联合体的每个对象互斥, 每个对象都有一个isa指针, 一个指针8字节, 一个字节占8位, 所占64位
进入isa_t的ISA_BITFIELD位域可以看到下面的结构
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 19
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
- nonpointer:表示是否对 isa 指针开启指针优化 0:纯isa指针,1:不止是类对象地址,isa 中包含了类信息、对象的引用计数等
- has_assoc:关联对象标志位,0没有,1存在
- has_cxx_dtor:该对象是否有 C++ 或者 Objc 的析构器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更快的释放对象
- shiftcls存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位用来存储类指针。
- magic用于调试器判断当前对象是真的对象还是没有初始化的空间
-
weakly_referenced志对象是否被指向或者曾经指向一个 ARC 的弱变量,
没有弱引用的对象可以更快释放。 - deallocating标志对象是否正在释放内存
- has_sidetable_rc当对象引用技术大于 10 时,则需要借用该变量存储进位
- extra_rc:当表示该对象的引用计数值,实际上是引用计数值减 1, 例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10, 则需要使用到下面的 has_sidetable_rc。
isa 是通过isa_t中的shiftclas这个属性存储了类信息, 通过initInstanceIsa方法把isa和cls之间进行了绑定

iOS是小端模式存储, 从低位开始, ①.如果要读取shfitclas则需要先右移3位,末尾抹零,左边则补齐3位,加上之前左边的17位,② 高位需要左移20位, 右边抹零, ③最后还原位置,右移17位

网友评论