一.背景
https://github.com/iOSPrincekin/KCObjc4_debug.git dev分支
二.地址
1.类的地址
1.编写测试代码
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *hooby;
@property (nonatomic, weak) NSString *dress;
@property (nonatomic, weak) LGPerson *son;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) double height;
@end
@implementation LGPerson
+(void)load{
NSLog(@"load--");
}
-(void)test1{
NSLog(@"test1--");
}
@end
LGPerson *globalPerson = nil;
void test1()
{
NSObject* son = [[LGPerson alloc]init];
[globalPerson setSon:son];
NSLog(@"globalPerson.son-:%p",globalPerson.son);
}
@interface Sark : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation Sark
- (void)speak {
NSLog(@"my name's %@", self.name);
}
@end
void test2()
{
Class obj_class = [NSObject class];
Class Sark_class = [Sark class];
id SarkMetaClass = objc_getMetaClass("Sark");
BOOL res1 = [(id)obj_class isKindOfClass:obj_class];
BOOL res2 = [(id)obj_class isMemberOfClass:obj_class];
BOOL res3 = [(id)Sark_class isKindOfClass:Sark_class];
BOOL res4 = [(id)Sark_class isMemberOfClass:Sark_class];
BOOL res5 = [(id)Sark_class isMemberOfClass:[Sark_class class]];
BOOL res6 = [(id)Sark_class isMemberOfClass:SarkMetaClass];
id Sark_class_class = [Sark_class class];
BOOL res7 = SarkMetaClass == Sark_class_class;
BOOL res8 = [[[Sark alloc]init] isMemberOfClass:Sark_class];
NSLog(@"%d %d %d %d %d %d %d %d", res1, res2, res3, res4, res5, res6, res7, res8);
}
@interface NSObject (Sark)
+ (void)foo;
@end
@implementation NSObject (Sark)
- (void)foo {
NSLog(@"IMP: -[NSObject (Sark) foo]");
}
@end
void test3()
{
// 测试代码
[NSObject foo];
[[NSObject new] foo];
}
void test4()
{
id cls = [Sark class];
void *obj = &cls;
[(__bridge id)obj test1];
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
globalPerson = [LGPerson alloc];
globalPerson.name = @"woshishui";
globalPerson.hooby = @"chifan";
globalPerson.dress = @"shuiyi";
test1();
globalPerson.age = 0x44;
globalPerson.height = 0x77;
[globalPerson test1];
[globalPerson.son test1];
NSLog(@"KCObjcBuild:%p",globalPerson);
test2();
test3();
// test4();
}
return 0;
}
2.ida分析可执行文件
可以看到 classlist 中包含 LGPerson 和 Sark
不需要懒加载的 类列表中即 nlclslist 总包含 LGPerson,因为 LGPerson 实现了 +load 方法,所以不需要懒加载,需要立即加载
分类类列表即 catlist 中包含 NSObject (Sark)
3.打印
在 readClass 方法中打印 LGPerson 类地址后输出
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
const char *mangledName = cls->nonlazyMangledName();
printf("cls:%p,mangledName:%s\n",cls,mangledName);
......
4.印证地址
cls:0x1000085a0,mangledName:LGPerson
此时在 lldb debug 状态下,执行 image list
(lldb) image list
[ 0] 2905B0F7-9E32-36D9-8717-18E1867196E4 0x0000000100000000 /Users/lee/Library/Developer/Xcode/DerivedData/objc-ascfiajdmnkqzabgrazgkmriraio/Build/Products/Debug/KCObjcBuild
0x1000085a0 - 0x0000000100000000 = 0x85a0
在ida中点击 classlist 中的LGPerson,跳转到如下地址
 bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 9.1
* frame #0: 0x000000010049c0f9 libobjc.A.dylib`realizeClassWithoutSwift(cls=0x0000000100008578, previously=0x0000000000000000) at objc-runtime-new.mm:2714:33
frame #1: 0x000000010049bfa5 libobjc.A.dylib`realizeClassWithoutSwift(cls=0x00000001000085a0, previously=0x0000000000000000) at objc-runtime-new.mm:2661:15
frame #2: 0x000000010049e3da libobjc.A.dylib`_read_images(hList=0x00007ff7bfefb3d0, hCount=56, totalClasses=2148, unoptimizedTotalClasses=2148) at objc-runtime-new.mm:3848:13
frame #3: 0x00000001004edb78 libobjc.A.dylib`map_images_nolock(mhCount=56, mhPaths=0x00007ff7bfefc570, mhdrs=0x00007ff7bfefca40, disabledClassROEnforcement=0x00007ff7bfefb6e7) at objc-os.mm:470:9
frame #4: 0x000000010049d021 libobjc.A.dylib`map_images(count=56, paths=0x00007ff7bfefc570, mhdrs=0x00007ff7bfefca40) at objc-runtime-new.mm:3161:9
frame #5: 0x00007ff801faa740 dyld`invocation function for block in dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*))::$_8::operator()() const + 637
frame #6: 0x00007ff801fa26d9 dyld`dyld4::RuntimeState::withLoadersReadLock(void () block_pointer) + 41
frame #7: 0x00007ff801fa75db dyld`dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*)) + 209
frame #8: 0x00007ff801fcd188 dyld`dyld4::APIs::_dyld_objc_register_callbacks(_dyld_objc_callbacks const*) + 138
frame #9: 0x00000001004eed3d libobjc.A.dylib`_objc_init at objc-os.mm:815:5
frame #10: 0x00000001000adfb9 libdispatch.dylib`_os_object_init + 13
frame #11: 0x00000001000bfd9c libdispatch.dylib`libdispatch_init + 363
frame #12: 0x00007ff80e15f898 libSystem.B.dylib`libSystem_initializer + 238
frame #13: 0x00007ff801fb43fb dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 175
frame #14: 0x00007ff801ff2b7a dyld`invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 242
frame #15: 0x00007ff801fe6f22 dyld`invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 577
frame #16: 0x00007ff801f970af dyld`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 245
frame #17: 0x00007ff801fe60bf dyld`dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 175
frame #18: 0x00007ff801ff273a dyld`dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 470
frame #19: 0x00007ff801fb166c dyld`dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 220
frame #20: 0x00007ff801fd2bdd dyld`dyld4::APIs::runAllInitializersForMain() + 65
frame #21: 0x00007ff801f9c874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
frame #22: 0x00007ff801f9b3bd dyld`start + 1805
从堆栈中可以看出是在 realizeClassWithoutSwift 方法中设置 cls->setInstanceSize(ro->instanceSize);
会先递归调用realizeClassWithoutSwift设置父类,再是子类
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 13.1
* frame #0: 0x00000001004cce66 libobjc.A.dylib`cache_t::setFastInstanceSize(this=0x00000001000085b0, newSize=56) at objc-runtime-new.h:595:18
frame #1: 0x00000001004b0942 libobjc.A.dylib`objc_class::setInstanceSize(this=0x00000001000085a0, newSize=56) at objc-runtime-new.h:2651:15
frame #2: 0x000000010049c01b libobjc.A.dylib`realizeClassWithoutSwift(cls=0x00000001000085a0, previously=0x0000000000000000) at objc-runtime-new.mm:2717:10
frame #3: 0x000000010049e2da libobjc.A.dylib`_read_images(hList=0x00007ff7bfefb3d0, hCount=56, totalClasses=2148, unoptimizedTotalClasses=2148) at objc-runtime-new.mm:3848:13
frame #4: 0x00000001004edb78 libobjc.A.dylib`map_images_nolock(mhCount=56, mhPaths=0x00007ff7bfefc570, mhdrs=0x00007ff7bfefca40, disabledClassROEnforcement=0x00007ff7bfefb6e7) at objc-os.mm:470:9
frame #5: 0x000000010049cf21 libobjc.A.dylib`map_images(count=56, paths=0x00007ff7bfefc570, mhdrs=0x00007ff7bfefca40) at objc-runtime-new.mm:3161:9
frame #6: 0x00007ff801faa740 dyld`invocation function for block in dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*))::$_8::operator()() const + 637
frame #7: 0x00007ff801fa26d9 dyld`dyld4::RuntimeState::withLoadersReadLock(void () block_pointer) + 41
frame #8: 0x00007ff801fa75db dyld`dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*)) + 209
frame #9: 0x00007ff801fcd188 dyld`dyld4::APIs::_dyld_objc_register_callbacks(_dyld_objc_callbacks const*) + 138
frame #10: 0x00000001004eed3d libobjc.A.dylib`_objc_init at objc-os.mm:815:5
frame #11: 0x00000001000adfb9 libdispatch.dylib`_os_object_init + 13
frame #12: 0x00000001000bfd9c libdispatch.dylib`libdispatch_init + 363
frame #13: 0x00007ff80e15f898 libSystem.B.dylib`libSystem_initializer + 238
frame #14: 0x00007ff801fb43fb dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 175
frame #15: 0x00007ff801ff2b7a dyld`invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 242
frame #16: 0x00007ff801fe6f22 dyld`invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 577
frame #17: 0x00007ff801f970af dyld`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 245
frame #18: 0x00007ff801fe60bf dyld`dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 175
frame #19: 0x00007ff801ff273a dyld`dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 470
frame #20: 0x00007ff801fb166c dyld`dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 220
frame #21: 0x00007ff801fd2bdd dyld`dyld4::APIs::runAllInitializersForMain() + 65
frame #22: 0x00007ff801f9c874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
frame #23: 0x00007ff801f9b3bd dyld`start + 1805
sizeBits = word_align(newSize) + FAST_CACHE_ALLOC_DELTA16;
会对齐 16字节,将 56 + FAST_CACHE_ALLOC_DELTA16 = 64
3.对象初始化
可以看到调用 calloc 进行对象内存的开辟,开辟大小为刚才设置 cls->setInstanceSize(ro->instanceSize); 的64字节,用于存储对应的属性值和ISA,同时将 ISA 指向 LGPerson 类
调用堆栈
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 19.1
frame #0: 0x000000010048cdcd libobjc.A.dylib`objc_object::initIsa(this=0x000060000170c540, cls=LGPerson, nonpointer=true, hasCxxDtor=true) at objc-object.h:364:5
frame #1: 0x00000001004b321e libobjc.A.dylib`objc_object::initInstanceIsa(this=0x000060000170c540, cls=LGPerson, hasCxxDtor=true) at objc-object.h:316:5
* frame #2: 0x00000001004b3617 libobjc.A.dylib`_objc_rootAllocWithZone [inlined] _class_createInstanceFromZone(cls=LGPerson, extraBytes=0, zone=0x0000000000000000, construct_flags=2, cxxConstruct=true, outAllocatedSize=0x0000000000000000) at objc-runtime-new.mm:8448:14
frame #3: 0x00000001004b349b libobjc.A.dylib`_objc_rootAllocWithZone(cls=LGPerson, zone=0x0000000000000000) at objc-runtime-new.mm:8475:12
frame #4: 0x00000001004fc2b4 libobjc.A.dylib`_objc_rootAlloc [inlined] callAlloc(cls=LGPerson, checkNil=false, allocWithZone=true) at NSObject.mm:2004:16
frame #5: 0x00000001004fc24c libobjc.A.dylib`_objc_rootAlloc(cls=LGPerson) at NSObject.mm:2020:12
frame #6: 0x00000001005000a9 libobjc.A.dylib`+[NSObject alloc](self=LGPerson, _cmd="alloc") at NSObject.mm:2682:12
frame #7: 0x00000001004fc3d4 libobjc.A.dylib`objc_alloc [inlined] callAlloc(cls=LGPerson, checkNil=true, allocWithZone=false) at NSObject.mm:2011:12
frame #8: 0x00000001004fc32c libobjc.A.dylib`objc_alloc(cls=LGPerson) at NSObject.mm:2027:12
frame #9: 0x0000000100003bcd KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:118:24 [opt]
frame #10: 0x00007ff801f9b41f dyld`start + 1903
shiftcls = (uintptr_t)newCls >> 3;
什么是isa?
arm64架构之前,isa就是个普通的指针,存储类对象和元类对象的内存地址 arm64架构之后,isa变成了一个联合体结构(union),并且使用了位域来存储更多的信息
isa_t是一个联合体(联合体中的变量共用同一块地址空间。也就是说,cls、bits、结构体共用同一块地址空间)
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
// 相当于是unsigned long bits;
uintptr_t bits;
#if defined(ISA_BITFIELD)
// 这里的定义在isa.h中,如下(注意uintptr_t实际上就是unsigned long)
// uintptr_t nonpointer : 1;
// uintptr_t has_assoc : 1;
// uintptr_t has_cxx_dtor : 1;
// uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
// uintptr_t magic : 6;
// uintptr_t weakly_referenced : 1;
// uintptr_t deallocating : 1;
// uintptr_t has_sidetable_rc : 1;
// uintptr_t extra_rc : 8
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
struct objc_object {
// isa结构体
private:
isa_t isa;
public:
// 类指针
// ISA() assumes this is NOT a tagged pointer object
Class ISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
...
}
objc_class(类对象结构体)继承objc_object(实例对象结构体)
// objc_class继承于objc_object,因此
// objc_class中也有isa结构体
struct objc_class : objc_object {
// ISA占8位
Class ISA;
// superclass占8位
Class superclass;
// 缓存的是指针和vtable,目的是加速方法的调用 cache占16位
cache_t cache; // formerly cache pointer and vtable
// class_data_bits_t 相当于是class_rw_t 指针加上rr/alloc标志
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
// 这里的bits就是class_data_bits_t bits;
return bits.data();
}
...
}
class_data_bits_t结构
class_data_bits_t用来存储数据,friend objc_class表明它有元类,uintptr_t bits通过掩码的形式保存class_rw_t是否是swift类等一些标志位
bool getBit(uintptr_t bit) const解析:
const 表示该方法内部不会修改 class_data_bits_t 的内部数据
返回值是一个 bool 类型,通过与操作来取出 bits 的指定位的值来进行判断
class_rw_t* data() const解析:
bits 中读出 class_rw_t 指针
void setData(class_rw_t *newData)解析:
设置class_rw_t 指针
struct class_data_bits_t {
friend objc_class;
// Values are the FAST_ flags above.
uintptr_t bits;
private:
bool getBit(uintptr_t bit) const
{
/*
内部实现只有一个与操作,主要根据入参 bit(掩码) 来取得一些标识位
如:
#define FAST_IS_SWIFT_LEGACY (1UL<<0)
使用 bit 的第 0 位来进行判断
#define FAST_IS_SWIFT_STABLE (1UL<<1)
bit 的 第 1 位 判断类是否是稳定的 Swift ABI 的 Swift 类
*/
return bits & bit;
}
public:
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
void setData(class_rw_t *newData) {
...
}
}
class_rw_t结构
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
// 请注意,Symbolication 知道此结构的布局。
// 在上篇的测试代码中:flags 打印看到是 2148007936
// 转为二进制的话是只有 31 位和 19 位是 1,其它位全部都是 0,对应于:
// class has started realizing but not yet completed it
// #define RW_REALIZING (1<<19)
// class_t->data is class_rw_t, not class_ro_t
// #define RW_REALIZED (1<<31)
uint32_t flags;
//(控制台打印值为 1)
uint16_t witness;
#if SUPPORT_INDEXED_ISA // isa 中保存 indexcls,大概是 watchOS 下才会用到
uint16_t index;
#endif
// std::atomic<uintptr_t>
// 原子性 unsigned long
// 执行如下命令,会打印 error:
// (lldb) p $2->ro_or_rw_ext
// error: no member named 'ro_or_rw_ext' in 'class_rw_t'
// 在编译时会根据类定义生成类的 class_ro_t 数据,其中包含方法列表、属性列表、成员变量列表等等内容
// ro_or_rw_ext 会有两种情况:
// 1): 编译时值是 class_ro_t *
// 2): 编译后类实现完成后值是 class_rw_ext_t *,而编译时的 class_ro_t * 作为 class_rw_ext_t 的 const class_ro_t *ro 成员变量保存
explicit_atomic<uintptr_t> ro_or_rw_ext; // 变量名字对应与 class_ro_t or(或) class_rw_ext_t
// 当前所属类的第一个子类
// 测试时,定义了一个继承自 NSObject 的类,
// 控制台打印看到它的 firstSubclass 是 nil
Class firstSubclass;
// 姊妹类、兄弟类
// 测试时,定义了一个继承自 NSObject 的类,
// 控制台打印看到 nextSiblingClass 是 NSUUID(好奇怪)
// firstSubclass 和 nextSiblingClass 有超级重要的作用,后面会展开
Class nextSiblingClass;
...
};
class_rw_t 的创建
在 realizeClassWithoutSwift 方法中
// Normal class. Allocate writeable class data.
rw = objc::zalloc<class_rw_t>();
rw->set_ro(ro);
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw);
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 11.1
* frame #0: 0x00000001004b1934 libobjc.A.dylib`objc_class::setData(this=0x00007ff8459d0740, newData=0x000060000022bf40) at objc-runtime-new.h:2190:9
frame #1: 0x000000010049bd69 libobjc.A.dylib`realizeClassWithoutSwift(cls=0x00007ff8459d0740, previously=0x0000000000000000) at objc-runtime-new.mm:2632:14
frame #2: 0x000000010049e2da libobjc.A.dylib`_read_images(hList=0x00007ff7bfefb3d0, hCount=56, totalClasses=2148, unoptimizedTotalClasses=2148) at objc-runtime-new.mm:3848:13
frame #3: 0x00000001004edb78 libobjc.A.dylib`map_images_nolock(mhCount=56, mhPaths=0x00007ff7bfefc570, mhdrs=0x00007ff7bfefca40, disabledClassROEnforcement=0x00007ff7bfefb6e7) at objc-os.mm:470:9
frame #4: 0x000000010049cf21 libobjc.A.dylib`map_images(count=56, paths=0x00007ff7bfefc570, mhdrs=0x00007ff7bfefca40) at objc-runtime-new.mm:3161:9
frame #5: 0x00007ff801faa740 dyld`invocation function for block in dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*))::$_8::operator()() const + 637
frame #6: 0x00007ff801fa26d9 dyld`dyld4::RuntimeState::withLoadersReadLock(void () block_pointer) + 41
frame #7: 0x00007ff801fa75db dyld`dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*)) + 209
frame #8: 0x00007ff801fcd188 dyld`dyld4::APIs::_dyld_objc_register_callbacks(_dyld_objc_callbacks const*) + 138
frame #9: 0x00000001004eed3d libobjc.A.dylib`_objc_init at objc-os.mm:815:5
frame #10: 0x00000001000adfb9 libdispatch.dylib`_os_object_init + 13
frame #11: 0x00000001000bfd9c libdispatch.dylib`libdispatch_init + 363
frame #12: 0x00007ff80e15f898 libSystem.B.dylib`libSystem_initializer + 238
frame #13: 0x00007ff801fb43fb dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 175
frame #14: 0x00007ff801ff2b7a dyld`invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 242
frame #15: 0x00007ff801fe6f22 dyld`invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 577
frame #16: 0x00007ff801f970af dyld`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 245
frame #17: 0x00007ff801fe60bf dyld`dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 175
frame #18: 0x00007ff801ff273a dyld`dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 470
frame #19: 0x00007ff801fb166c dyld`dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 220
frame #20: 0x00007ff801fd2bdd dyld`dyld4::APIs::runAllInitializersForMain() + 65
frame #21: 0x00007ff801f9c874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
frame #22: 0x00007ff801f9b3bd dyld`start + 1805
class_rw_ext_t结构
struct class_rw_ext_t {
// 特别关注 ro 这个成员变量。
// 这个即是在类实现完成后,class_rw_t 中存放的编译器生成的 class_ro_t 数据。
const class_ro_t *ro;
// 在上一节 class_ro_t 中的:
// 方法列表、属性列表、成员变量列表、协议列表的类型如下:
// struct method_list_t : entsize_list_tt<method_t, method_list_t, 0x3>
// struct property_list_t : entsize_list_tt<property_t, property_list_t, 0>
// struct ivar_list_t : entsize_list_tt<ivar_t, ivar_list_t, 0>
// struct protocol_list_t
// 到 class_rw_t 中就变为了:
// class method_array_t : public list_array_tt<method_t, method_list_t>
// class property_array_t : public list_array_tt<property_t, property_list_t>
// class protocol_array_t : public list_array_tt<protocol_ref_t, protocol_list_t>
// 这里先不着急,等下会详细分析它们所使用的新的数据结构: list_array_tt。
// 方法列表
method_array_t methods;
// 属性列表
property_array_t properties;
// 协议列表
protocol_array_t protocols;
// 所属的类名
char *demangledName;
// 版本号
uint32_t version;
};
class_ro_t & class_rw_t & class_rw_ext_t & Class之间的关系
要了解它们之间的关系,我们首先要了解几个关键跟它们相关的概念。
名词解析
从字面意思解读:class_ro_t中的“ro”代表只读;class_rw_t中的“rw”代表可读可写;class_rw_ext_t中的“rw_ext”代表可读可写的扩展。
干净内存和脏内存:干净内存内存指的是内存一旦加载就不会被改变。反之,脏内存就是在运行时会被修改的。
关系释疑
Class本身是运行时加载的,在运行时会被改变,所以本身Class就是属于脏内存。那么如果想要获取Class的干净内存,也就是编译时确定的数据结构包括方法列表、成员变量等的,该怎么办?
这其实就是class_ro_t的作用。因为class_ro_t是只读,意味着 class_ro_t是从mach-o读取类的数据之后,就不会被改变。那如果我们想在运行时修改类的信息,比如添加方法,比如加载category怎么办呢?那这时候就有一个与之对应的class_rw_t结构,class_rw_t可以在运行时存储类的信息,可读可写的,可以在运行时修改。
说到这里,好像还漏掉一个结构class_rw_ext_t,这个东西又是干什么用的呢?存在的意义是什么?其实还是跟运行时有关。实际上在我们的app运行中,需要运行时修改的类是非常少的,据统计平均大概就10%左右。那也就是说大部分只需要读取class_ro_t中的数据就够了,少部分才需要修改。因此才会有class_rw_ext_t这个扩展的结构体。class_rw_ext_t的作用是这样的:当我们需要修改类结构时,比如添加方法、加载category等时,class_rw_t回去开辟一个额外的空间rwe(class_rw_ext_t),用于存储新的方法和class_ro_t中的方法等信息。这样做的目的有一个好处就是,对于绝大部分类是不需要这个开辟class_rw_ext_t这个结构体,节省内存。
创建时机
那这几个结构分别是什么时候创建的呢?这里就设计到类的加载流程。首先类在app启动的时候会被映射到内存,这时候会先创建Class(objc_class)结构,然后把类编译时的类数据映射到class_ro_t,class_ro_t结构体指针存储到Class的bits指针中,我们前面提到类的bits中存储的是class_rw_t指针,实际上在类初始化之前这里存储的是class_ro_t,等到类初始化的时候会创建一个class_rw_t结构,然后通过data()从bits中读取class_ro_t,然后class_rw_t通过set_ro(const class_ro_t *ro)把指针ro_or_rw_ext指向这个class_ro_t,然后Class通过setData()把class_rw_t指针存储到bits里面。然后在运行时根据需要,根据extAllocIfNeeded或extAlloc创建class_rw_ext_t,然后把class_ro_t关联到class_rw_ext_t,这就是大概流程。OC类的加载流程
3.分类是如何将方法添加到对应的类中的
1.找到分类对应的类
Class cls = remapClass(cat->cls);
1.class_rw_t::extAlloc(const class_ro_t *ro, bool deepCopy)方法中创建 class_rw_ext_t 用于接收分类方法
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 10.1
* frame #0: 0x000000010049a892 libobjc.A.dylib`class_rw_t::extAlloc(this=0x0000600000233040, ro=0x00007ff845244068, deepCopy=false) at objc-runtime-new.mm:1386:9
frame #1: 0x00000001004a8f9c libobjc.A.dylib`class_rw_t::extAllocIfNeeded(this=0x0000600000233040) at objc-runtime-new.h:1834:20
frame #2: 0x00000001004c419f libobjc.A.dylib`attachCategories(cls=0x00007ff8459e2c10, cats_list=0x00007ff7bfefd508, cats_count=1, flags=8) at objc-runtime-new.mm:1446:29
frame #3: 0x00000001004c6485 libobjc.A.dylib`load_categories_nolock(header_info*)::$_10::operator()(this=0x00007ff7bfefd550, catlist=0x00007ffb43bc1d38) const at objc-runtime-new.mm:3235:25
frame #4: 0x000000010049f123 libobjc.A.dylib`load_categories_nolock(hi=0x000060000260c600) at objc-runtime-new.mm:3254:5
frame #5: 0x000000010049d0ba libobjc.A.dylib`loadAllCategories() at objc-runtime-new.mm:3262:9
frame #6: 0x000000010049cfd6 libobjc.A.dylib`load_images(path="/usr/lib/system/libsystem_blocks.dylib", mh=0x00007ff80202e000) at objc-runtime-new.mm:3280:9
frame #7: 0x00007ff801fa76d8 dyld`dyld4::RuntimeState::notifyObjCInit(dyld4::Loader const*) + 170
frame #8: 0x00007ff801fd2c6f dyld`dyld4::APIs::runAllInitializersForMain() + 211
frame #9: 0x00007ff801f9c874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
frame #10: 0x00007ff801f9b3bd dyld`start + 1805
在 attachLists 分类之前 ro_or_rw_ext 指向 class_ro_t, attachLists 分类之后 ro_or_rw_ext 指向 class_rw_ext_t,并将 class_ro_t 设置给 class_rw_ext_t
void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {
// the release barrier is so that the class_rw_ext_t::ro initialization
// is visible to lockless readers
rwe->ro = ro;
ro_or_rw_ext_t{rwe, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_release);
}
set_ro_or_rwe(rwe, ro);
2.先合并 class_ro_t 中内容
property_list_t *proplist = ro->baseProperties;
if (proplist) {
rwe->properties.attachLists(&proplist, 1);
}
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 9.2
* frame #0: 0x000000010049aceb libobjc.A.dylib`list_array_tt<property_t, property_list_t, RawPtr>::attachLists(this=0x0000600000c140d0, addedLists=0x00007ff7bfefcda0, addedCount=1) at objc-runtime-new.h:1653:24
frame #1: 0x000000010049a8f7 libobjc.A.dylib`class_rw_t::extAlloc(this=0x0000600000233040, ro=0x00007ff845244068, deepCopy=false) at objc-runtime-new.mm:1398:25
frame #2: 0x00000001004a8f9c libobjc.A.dylib`class_rw_t::extAllocIfNeeded(this=0x0000600000233040) at objc-runtime-new.h:1834:20
frame #3: 0x00000001004c419f libobjc.A.dylib`attachCategories(cls=0x00007ff8459e2c10, cats_list=0x00007ff7bfefd508, cats_count=1, flags=8) at objc-runtime-new.mm:1446:29
frame #4: 0x00000001004c6485 libobjc.A.dylib`load_categories_nolock(header_info*)::$_10::operator()(this=0x00007ff7bfefd550, catlist=0x00007ffb43bc1d38) const at objc-runtime-new.mm:3235:25
frame #5: 0x000000010049f123 libobjc.A.dylib`load_categories_nolock(hi=0x000060000260c600) at objc-runtime-new.mm:3254:5
frame #6: 0x000000010049d0ba libobjc.A.dylib`loadAllCategories() at objc-runtime-new.mm:3262:9
frame #7: 0x000000010049cfd6 libobjc.A.dylib`load_images(path="/usr/lib/system/libsystem_blocks.dylib", mh=0x00007ff80202e000) at objc-runtime-new.mm:3280:9
frame #8: 0x00007ff801fa76d8 dyld`dyld4::RuntimeState::notifyObjCInit(dyld4::Loader const*) + 170
frame #9: 0x00007ff801fd2c6f dyld`dyld4::APIs::runAllInitializersForMain() + 211
frame #10: 0x00007ff801f9c874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
frame #11: 0x00007ff801f9b3bd dyld`start + 1805
3.再合并分类中的内容
auto& entry = cats_list[i];
method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
rwe->methods.attachLists(mlists + ATTACH_BUFSIZ - mcount, mcount);
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 9.1
frame #0: 0x000000010049aa5b libobjc.A.dylib`list_array_tt<method_t, method_list_t, method_list_t_authed_ptr>::attachLists(this=0x0000600000c140c8, addedLists=0x00007ff7bfefd4a8, addedCount=1) at objc-runtime-new.h:1653:24
* frame #1: 0x00000001004c448b libobjc.A.dylib`attachCategories(cls=0x00007ff8459e2c10, cats_list=0x00007ff7bfefd508, cats_count=1, flags=8) at objc-runtime-new.mm:1485:22
frame #2: 0x00000001004c6485 libobjc.A.dylib`load_categories_nolock(header_info*)::$_10::operator()(this=0x00007ff7bfefd550, catlist=0x00007ffb43bc1d38) const at objc-runtime-new.mm:3235:25
frame #3: 0x000000010049f123 libobjc.A.dylib`load_categories_nolock(hi=0x000060000260c600) at objc-runtime-new.mm:3254:5
frame #4: 0x000000010049d0ba libobjc.A.dylib`loadAllCategories() at objc-runtime-new.mm:3262:9
frame #5: 0x000000010049cfd6 libobjc.A.dylib`load_images(path="/usr/lib/system/libsystem_blocks.dylib", mh=0x00007ff80202e000) at objc-runtime-new.mm:3280:9
frame #6: 0x00007ff801fa76d8 dyld`dyld4::RuntimeState::notifyObjCInit(dyld4::Loader const*) + 170
frame #7: 0x00007ff801fd2c6f dyld`dyld4::APIs::runAllInitializersForMain() + 211
frame #8: 0x00007ff801f9c874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
frame #9: 0x00007ff801f9b3bd dyld`start + 1805
4.对象如何找到对应方法
调用没有实现的 -[LGPerson test2]
1.首先会调用 objc_msgSend 方法
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 4.1
* frame #0: 0x00000001004e6c86 libobjc.A.dylib`objc_msgSend at objc-msg-x86_64.s:732
frame #1: 0x0000000100003bfc KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:119:22 [opt]
frame #2: 0x00007ff801f9b41f dyld`start + 1903
通过 objc_msgSend 中的 GetIsaFast NORMAL // r10 = self->isa 获取到对象的 class
2.调用 lookUpImpOrForward 方法查找对应SEL
static method_t *
getMethodNoSuper_nolock(Class cls, SEL sel)
{
lockdebug::assert_locked(&runtimeLock);
ASSERT(cls->isRealized());
// fixme nil cls?
// fixme nil sel?
auto const methods = cls->data()->methods();
for (auto mlists = methods.beginLists(),
end = methods.endLists();
mlists != end;
++mlists)
{
// <rdar://problem/46904873> getMethodNoSuper_nolock is the hottest
// caller of search_method_list, inlining it turns
// getMethodNoSuper_nolock into a frame-less function and eliminates
// any store from this codepath.
method_t *m = search_method_list_inline(*mlists, sel);
if (m) return m;
}
return nil;
}
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 10.1
* frame #0: 0x00000001004ad6b0 libobjc.A.dylib`getMethodNoSuper_nolock(cls=LGPerson, sel="setName:") at objc-runtime-new.mm:6527:13
frame #1: 0x00000001004abe3a libobjc.A.dylib`lookUpImpOrForward(inst=0x000060000170c440, sel="setName:", cls=LGPerson, behavior=3) at objc-runtime-new.mm:6903:30
frame #2: 0x00000001004e781b libobjc.A.dylib`_objc_msgSend_uncached at objc-msg-x86_64.s:1153
frame #3: 0x0000000100003bfc KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:119:22 [opt]
frame #4: 0x00007ff801f9b41f dyld`start + 1903
循环到查找父类中有有没有方法,一直到父类不存在或找到为止为止
NEVER_INLINE
IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
{
...
const IMP forward_imp = (IMP)_objc_msgForward_impcache;
IMP imp = nil;
for (unsigned attempts = unreasonableClassCount();;) {
if (slowpath((curClass = curClass->getSuperclass()) == nil)) {
// 找不到如何实现,resolveInstanceMethod方法实现也没找到,则 将 forward_imp 赋值给 imp ,调用 _objc_msgForward_impcache 方法转发
imp = forward_imp;
break;
}
// Superclass cache.
imp = cache_getImp(curClass, sel);
if (slowpath(imp == forward_imp)) {
// Found a forward:: entry in a superclass.
// Stop searching, but don't cache yet; call method
// resolver for this class first.
break;
}
...
}
}
3.找不到方法的处理
1.找到方法,则跳转到结束
// curClass method list.
method_t *meth = getMethodNoSuper_nolock(curClass, sel);
if (meth) {
imp = meth->imp(false);
goto done;
}
2.找不到方法,则进行转发
对象方法使用 resolveInstanceMethod 进行转发
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00000001004cb263 libobjc.A.dylib`resolveInstanceMethod(inst=0x0000600001708180, sel="test2", cls=LGPerson) at objc-runtime-new.mm:6657:5
frame #1: 0x00000001004ad74d libobjc.A.dylib`resolveMethod_locked(inst=0x0000600001708180, sel="test2", cls=LGPerson, behavior=1) at objc-runtime-new.mm:6708:9
frame #2: 0x00000001004abee4 libobjc.A.dylib`lookUpImpOrForward(inst=0x0000600001708180, sel="test2", cls=LGPerson, behavior=1) at objc-runtime-new.mm:6943:16
frame #3: 0x00000001004e77db libobjc.A.dylib`_objc_msgSend_uncached at objc-msg-x86_64.s:1153
frame #4: 0x0000000100003bd5 KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:124:9 [opt]
frame #5: 0x00007ff8001ed41f dyld`start + 1903
查看 对象的 class 和 元类 class 有没有实现 对象方法 resolveInstanceMethod
static void resolveInstanceMethod(id inst, SEL sel, Class cls)
{
lockdebug::assert_unlocked(&runtimeLock);
ASSERT(cls->isRealized());
SEL resolve_sel = @selector(resolveInstanceMethod:);
if (!lookUpImpOrNilTryCache(cls, resolve_sel, cls->ISA(/*authenticated*/true))) {
// Resolver not implemented.
return;
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, resolve_sel, sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveInstanceMethod adds to self a.k.a. cls
IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
* frame #0: 0x00000001004abe57 libobjc.A.dylib`lookUpImpOrForward(inst=0x0000600001708180, sel="test2", cls=LGPerson, behavior=4) at objc-runtime-new.mm:6923:54
frame #1: 0x00000001004ac1ed libobjc.A.dylib`lookUpImpOrNilTryCache [inlined] _lookUpImpTryCache(inst=0x0000600001708180, sel="test2", cls=LGPerson, behavior=4) at objc-runtime-new.mm:6810:16
frame #2: 0x00000001004ac168 libobjc.A.dylib`lookUpImpOrNilTryCache(inst=0x0000600001708180, sel="test2", cls=LGPerson, behavior=0) at objc-runtime-new.mm:6827:12
frame #3: 0x00000001004cb323 libobjc.A.dylib`resolveInstanceMethod(inst=0x0000600001708180, sel="test2", cls=LGPerson) at objc-runtime-new.mm:6670:15
frame #4: 0x00000001004ad74d libobjc.A.dylib`resolveMethod_locked(inst=0x0000600001708180, sel="test2", cls=LGPerson, behavior=1) at objc-runtime-new.mm:6708:9
frame #5: 0x00000001004abee4 libobjc.A.dylib`lookUpImpOrForward(inst=0x0000600001708180, sel="test2", cls=LGPerson, behavior=1) at objc-runtime-new.mm:6943:16
frame #6: 0x00000001004e77db libobjc.A.dylib`_objc_msgSend_uncached at objc-msg-x86_64.s:1153
frame #7: 0x0000000100003bd5 KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:124:9 [opt]
frame #8: 0x00007ff8001ed41f dyld`start + 1903
如果没有实现 resolveInstanceMethod,则会调用 _objc_msgForward_impcache ,接着调用 _CF_forwarding_prep_0
寻找 forwardingTargetForSelector: 方法
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 6.1
frame #0: 0x00000001004abe70 libobjc.A.dylib`lookUpImpOrForward(inst=0x0000000000000000, sel="forwardingTargetForSelector:", cls=LGSon, behavior=6) at objc-runtime-new.mm:6926:28
frame #1: 0x00000001004ac1ed libobjc.A.dylib`lookUpImpOrNilTryCache [inlined] _lookUpImpTryCache(inst=0x0000000000000000, sel="forwardingTargetForSelector:", cls=LGSon, behavior=6) at objc-runtime-new.mm:6810:16
frame #2: 0x00000001004ac168 libobjc.A.dylib`lookUpImpOrNilTryCache(inst=0x0000000000000000, sel="forwardingTargetForSelector:", cls=LGSon, behavior=2) at objc-runtime-new.mm:6827:12
frame #3: 0x000000010048abea libobjc.A.dylib`class_respondsToSelector_inst(inst=0x0000000000000000, sel="forwardingTargetForSelector:", cls=LGSon) at objc-class.mm:662:26
frame #4: 0x000000010048ab91 libobjc.A.dylib`class_respondsToSelector(cls=LGSon, sel="forwardingTargetForSelector:") at objc-class.mm:651:12
* frame #5: 0x00007ff8006052da CoreFoundation`___forwarding___ + 179
frame #6: 0x00007ff800605198 CoreFoundation`_CF_forwarding_prep_0 + 120
frame #7: 0x0000000100003bd5 KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:138:9 [opt]
frame #8: 0x00007ff8001ed41f dyld`start + 1903
如果类没有实现forwardingTargetForSelector方法,则会调用NSObject 的 forwardingTargetForSelector 方法 ,在 NSObject.mm 中 forwardingTargetForSelector 返回了空对象
+ (id)forwardingTargetForSelector:(SEL)sel {
return nil;
}
- (id)forwardingTargetForSelector:(SEL)sel {
return nil;
}
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
* frame #0: 0x00000001004ffc90 libobjc.A.dylib`-[NSObject forwardingTargetForSelector:](self=0x000060000171c000, _cmd="forwardingTargetForSelector:", sel="test2") at NSObject.mm:2586:5
frame #1: 0x00007ff8006052f1 CoreFoundation`___forwarding___ + 202
frame #2: 0x00007ff800605198 CoreFoundation`_CF_forwarding_prep_0 + 120
frame #3: 0x0000000100003bd5 KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:138:9 [opt]
frame #4: 0x00007ff8001ed41f dyld`start + 1903
接着会查找当前类是否实现 methodSignatureForSelector,如果没有找到则调用当前对象的 forwardInvocation方法包装后 进行转发
loc_116064:
//**rbx就是实例对象,放到var_138暂存**
var_138 = rbx;
if (strncmp(r12, "_NSZombie_", 0xa) == 0x0) goto loc_1163cd;
loc_116087:
//**r14 = 实例对象,r15 = 类对象**
r14 = var_138;
//**类对象是否响应methodSignatureForSelector方法**
//**所以通过上面代码我们知道这是当forwardingTargetForSelector没匹配方法成功时调用**
//**我们把这里成为慢速消息转发**
if (class_respondsToSelector(r15, @selector(methodSignatureForSelector:)) == 0x0) goto loc_1163e3;
loc_1160a8:
//**这里的rbx又等于SEL了**
rbx = var_140;
//**调用methodSignatureForSelector方法**
rax = [r14 methodSignatureForSelector:rbx];
//**返回值为0x0,则去loc_11645e位置**
if (rax == 0x0) goto loc_11645e;
loc_1160c7:
r15 = rax;
rax = [rax _frameDescriptor];
r12 = rax;
if (((*(int16_t *)(*rax + 0x22) & 0xffff) >> 0x6 & 0x1) != r13) {
rax = sel_getName(rbx);
rcx = "";
if ((*(int16_t *)(*r12 + 0x22) & 0xffff & 0x40) == 0x0) {
rcx = " not";
}
r8 = "";
if (r13 == 0x0) {
r8 = " not";
}
_CFLog(0x4, @"*** NSForwarding: warning: method signature and compiler disagree on struct-return-edness of '%s'. Signature thinks it does%s return a struct, and compiler thinks it does%s.", rax, rcx, r8, r9, var_150);
}
//**_forwardStackInvocation带下划线的基本都是系统内部函数**
if (class_respondsToSelector(object_getClass(r14), @selector(_forwardStackInvocation:)) == 0x0) goto loc_1161fe;
loc_1161fe:
var_150 = r12;
r12 = r14;
if (class_respondsToSelector(object_getClass(r14), @selector(forwardInvocation:)) == 0x0) goto loc_11642b;
loc_11622a:
//**准备forwardInvocation方法需要的参数**
rax = [NSInvocation _invocationWithMethodSignature:r15 frame:var_148];
r13 = rax;
//**调用forwardInvocation方法**
[r12 forwardInvocation:rax];
var_140 = 0x0;
rbx = 0x0;
r12 = var_150;
goto loc_11626b;
loc_11642b:
r14 = @selector(forwardInvocation:);
____forwarding___.cold.4(&var_130, r12);
rcx = r14;
_CFLog(0x4, @"*** NSForwarding: warning: object %p of class '%s' does not implement methodSignatureForSelector: -- trouble ahead", var_138, rcx, r8, r9, var_150);
goto loc_116457;
如果在找不到,则会报错 doesNotRecognizeSelector 触发崩溃
loc_116457:
rbx = var_140;
goto loc_11645e;
loc_11645e:
rax = sel_getName(rbx);
r14 = rax;
rax = sel_getUid(rax);
if (rax != rbx) {
rcx = r14;
r8 = rax;
_CFLog(0x4, @"*** NSForwarding: warning: selector (%p) for message '%s' does not match selector known to Objective C runtime (%p)-- abort", var_140, rcx, r8, r9, var_150);
}
if (class_respondsToSelector(object_getClass(var_138), @selector(doesNotRecognizeSelector:)) == 0x0) goto loc_1164d1;
loc_1164b8:
(*_objc_msgSend)(var_138, @selector(doesNotRecognizeSelector:));
asm { ud2 };
rax = loc_1164d1(rdi, rsi, rdx, rcx, r8, r9);
return rax;
5.initialize方法调用时机
globalPerson = [LGPerson alloc]; 会调用 initialize方法
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00000001004abc30 libobjc.A.dylib`lookUpImpOrForward(inst=0x00000001000085a0, sel="initialize", cls=0x0000000100008578, behavior=3) at objc-runtime-new.mm:6836:33
frame #1: 0x00000001004e781b libobjc.A.dylib`_objc_msgSend_uncached at objc-msg-x86_64.s:1153
frame #2: 0x00000001004923ec libobjc.A.dylib`_CALLING_SOME_+initialize_METHOD(cls=LGPerson) at objc-initialize.mm:384:5
frame #3: 0x0000000100492931 libobjc.A.dylib`initializeNonMetaClass(cls=LGPerson) at objc-initialize.mm:549:13
frame #4: 0x000000010049b59e libobjc.A.dylib`initializeAndMaybeRelock(cls=0x0000000100008578, inst=0x00000001000085a0, lock=0x000000010051b0c0, leaveLocked=true) at objc-runtime-new.mm:2216:5
frame #5: 0x00000001004cb28a libobjc.A.dylib`initializeAndLeaveLocked(cls=0x0000000100008578, obj=0x00000001000085a0, lock=0x000000010051b0c0) at objc-runtime-new.mm:2232:12
frame #6: 0x00000001004ac320 libobjc.A.dylib`realizeAndInitializeIfNeeded_locked(inst=0x00000001000085a0, cls=0x0000000100008578, initialize=true) at objc-runtime-new.mm:6765:15
frame #7: 0x00000001004abdd9 libobjc.A.dylib`lookUpImpOrForward(inst=0x00000001000085a0, sel="alloc", cls=0x0000000100008578, behavior=11) at objc-runtime-new.mm:6882:11
frame #8: 0x00000001004e781b libobjc.A.dylib`_objc_msgSend_uncached at objc-msg-x86_64.s:1153
frame #9: 0x00000001004fc3d4 libobjc.A.dylib`objc_alloc [inlined] callAlloc(cls=LGPerson, checkNil=true, allocWithZone=false) at NSObject.mm:2011:12
frame #10: 0x00000001004fc32c libobjc.A.dylib`objc_alloc(cls=LGPerson) at NSObject.mm:2027:12
* frame #11: 0x0000000100003bcd KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:118:24 [opt]
frame #12: 0x00007ff801f9b41f dyld`start + 1903