同isa一样从源码入手,首先从源码中找到类Class的定义和结构
// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
// A pointer to an instance of a class.
typedef struct objc_object *id;
继续找objc_class
struct objc_class : objc_object {
// Class ISA; //隐性存在(继承而来)的isa 占8个字节
Class superclass; //父类对象地址 占8个字节
cache_t cache; //16个字节 // pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
//省略其他
}
cache_t
struct cache_t {
//typedef uint32_t mask_t;
struct bucket_t *_buckets; //指针8个字节
mask_t _mask; //uint32_t 4个字节
mask_t _occupied; //uint32_t 4个字节
public:
struct bucket_t *buckets();
mask_t mask();
mask_t occupied();
void incrementOccupied();
void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
void initializeToEmpty();
mask_t capacity();
bool isConstantEmptyCache();
bool canBeFreed();
static size_t bytesForCapacity(uint32_t cap);
static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
void expand();
void reallocate(mask_t oldCapacity, mask_t newCapacity);
struct bucket_t * find(SEL sel, id receiver);
static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));
};
class_rw_t
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
#if SUPPORT_INDEXED_ISA
uint32_t index;
#endif
void setFlags(uint32_t set)
{
OSAtomicOr32Barrier(set, &flags);
}
void clearFlags(uint32_t clear)
{
OSAtomicXor32Barrier(clear, &flags);
}
// set and clear must not overlap
void changeFlags(uint32_t set, uint32_t clear)
{
assert((set & clear) == 0);
uint32_t oldf, newf;
do {
oldf = flags;
newf = (oldf | set) & ~clear;
} while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
}
};
找const class_ro_t *ro;
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
// This field exists only when RO_HAS_SWIFT_INITIALIZER is set.
_objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];
_objc_swiftMetadataInitializer swiftMetadataInitializer() const {
if (flags & RO_HAS_SWIFT_INITIALIZER) {
return _swiftMetadataInitializer_NEVER_USE[0];
} else {
return nil;
}
}
method_list_t *baseMethods() const {
return baseMethodList;
}
class_ro_t *duplicate() const {
if (flags & RO_HAS_SWIFT_INITIALIZER) {
size_t size = sizeof(*this) + sizeof(_swiftMetadataInitializer_NEVER_USE[0]);
class_ro_t *ro = (class_ro_t *)memdup(this, size);
ro->_swiftMetadataInitializer_NEVER_USE[0] = this->_swiftMetadataInitializer_NEVER_USE[0];
return ro;
} else {
size_t size = sizeof(*this);
class_ro_t *ro = (class_ro_t *)memdup(this, size);
return ro;
}
}
};
通过lldb开始探索
首先定义Person如下
@interface Person : NSObject
{
NSString *secondName;
}
@property (nonatomic, copy) NSString *firstName;
+ (void)walk;
- (void)fly;
1.查看Person类的内存
(lldb) x/4gx p.class
0x1000012d8: 0x001d8001000012b1 0x0000000100b36140
0x1000012e8: 0x0000000102d52a70 0x0000000300000003
2.通过内存偏移找到bits的内存地址,需要偏移的字节数有ISA 8个字节,superclass 8个字节, cache_t 16个字节,0x1000012d8 + 32 = 0x1000012f8
(lldb) p (class_data_bits_t *)0x1000012f8
(class_data_bits_t *) $1 = 0x00000001000012f8
3.找到class_rw_t
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000102d52370
(lldb) p *$2
(class_rw_t) $3 = {
flags = 2148139008
version = 0
ro = 0x00000001000011b0
methods = {
list_array_tt<method_t, method_list_t> = {
= {
list = 0x00000001000010e8
arrayAndFlag = 4294971624
}
}
}
properties = {
list_array_tt<property_t, property_list_t> = {
= {
list = 0x0000000100001198
arrayAndFlag = 4294971800
}
}
}
protocols = {
list_array_tt<unsigned long, protocol_list_t> = {
= {
list = 0x0000000000000000
arrayAndFlag = 0
}
}
}
firstSubclass = nil
nextSiblingClass = NSUUID
demangledName = 0x0000000000000000 <no value available>
}
5.找其中的ro
(lldb) p $3.ro
(const class_ro_t *) $4 = 0x00000001000011b0
(lldb) p *$4
(const class_ro_t) $5 = {
flags = 388
instanceStart = 8
instanceSize = 24
reserved = 0
ivarLayout = 0x0000000100000efb "\x02"
name = 0x0000000100000ef4 "Person"
baseMethodList = 0x00000001000010e8
baseProtocols = 0x0000000000000000
ivars = 0x0000000100001150
weakIvarLayout = 0x0000000000000000 <no value available>
baseProperties = 0x0000000100001198
_swiftMetadataInitializer_NEVER_USE = {}
}
6.找其中的baseProperties
(lldb) p $5.baseProperties
(property_list_t *const) $6 = 0x0000000100001198
(lldb) p *$6
(property_list_t) $7 = {
entsize_list_tt<property_t, property_list_t, 0> = {
entsizeAndFlags = 16
count = 1
first = (name = "firstName", attributes = "T@"NSString",C,N,V_firstName")
}
}
7.查看成员变量ivars
(lldb) p $5.ivars
(const ivar_list_t *const) $8 = 0x0000000100001150
(lldb) p *$8
(const ivar_list_t) $9 = {
entsize_list_tt<ivar_t, ivar_list_t, 0> = {
entsizeAndFlags = 32
count = 2
first = {
offset = 0x00000001000012a8
name = 0x0000000100000f35 "secondName"
type = 0x0000000100000f71 "@"NSString""
alignment_raw = 3
size = 8
}
}
}
8.查看方法列表baseMethodList
(lldb) p $5.baseMethodList
(method_list_t *const) $10 = 0x00000001000010e8
(lldb) p *$10
(method_list_t) $11 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 26
count = 4
first = {
name = "fly"
types = 0x0000000100000f56 "v16@0:8"
imp = 0x0000000100000d20 (objc-debug`-[Person fly] at Person.m:17)
}
}
}
(lldb) p $10.get(0)
(method_t) $12 = {
name = "fly"
types = 0x0000000100000f56 "v16@0:8"
imp = 0x0000000100000d20 (objc-debug`-[Person fly] at Person.m:17)
}
Fix-it applied, fixed expression was:
$10->get(0)
(lldb) p $10.get(1)
(method_t) $13 = {
name = ".cxx_destruct"
types = 0x0000000100000f56 "v16@0:8"
imp = 0x0000000100000da0 (objc-debug`-[Person .cxx_destruct] at Person.m:11)
}
Fix-it applied, fixed expression was:
$10->get(1)
(lldb) p $10.get(2)
(method_t) $14 = {
name = "firstName"
types = 0x0000000100000f5e "@16@0:8"
imp = 0x0000000100000d30 (objc-debug`-[Person firstName] at Person.h:18)
}
Fix-it applied, fixed expression was:
$10->get(2)
(lldb) p $10.get(3)
(method_t) $15 = {
name = "setFirstName:"
types = 0x0000000100000f66 "v24@0:8@16"
imp = 0x0000000100000d60 (objc-debug`-[Person setFirstName:] at Person.h:18)
}
Fix-it applied, fixed expression was:
$10->get(3)
(lldb) p $10.get(4)
Assertion failed: (i < count), function get, file /Users/tiltwang/Documents/runtime/objc-runtime-new.h, line 140.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
并没有找到类方法walk,那么去元类中查找
(lldb) x/4gx p
0x102f70200: 0x001d8001000012fd 0x0000000000000000
0x102f70210: 0x0000000100001048 0x0000000000000000
(lldb) p/x 0x001d8001000012fd & 0x00007ffffffffff8ULL
(unsigned long long) $1 = 0x00000001000012f8
(lldb) x/4gx $1
0x1000012f8: 0x001d8001000012d1 0x0000000100b36140
0x100001308: 0x0000000102f748b0 0x0000000100000003
(lldb) p/x 0x001d8001000012d1 & 0x00007ffffffffff8ULL
(unsigned long long) $2 = 0x00000001000012d0
(lldb) x/4gx $2
0x1000012d0: 0x001d800100b360f1 0x0000000100b360f0
0x1000012e0: 0x0000000102f741f0 0x0000000100000003
(lldb) p/x 0x001d800100b360f1 & 0x00007ffffffffff8ULL
(unsigned long long) $3 = 0x0000000100b360f0
(lldb) po $3
NSObject
(lldb) p (class_data_bits_t *)0x1000012f0
(class_data_bits_t *) $4 = 0x00000001000012f0
(lldb) p $4->data()
(class_rw_t *) $5 = 0x0000000102f74150
(lldb) p *$5
(class_rw_t) $6 = {
flags = 2685075456
version = 7
ro = 0x00000001000010c0
methods = {
list_array_tt<method_t, method_list_t> = {
= {
list = 0x00000001000010a0
arrayAndFlag = 4294971552
}
}
}
properties = {
list_array_tt<property_t, property_list_t> = {
= {
list = 0x0000000000000000
arrayAndFlag = 0
}
}
}
protocols = {
list_array_tt<unsigned long, protocol_list_t> = {
= {
list = 0x0000000000000000
arrayAndFlag = 0
}
}
}
firstSubclass = nil
nextSiblingClass = 0x00007fff917f99b0
demangledName = 0x0000000000000000 <no value available>
}
(lldb) p $6.ro
(const class_ro_t *) $7 = 0x00000001000010c0
(lldb) p *$7
(const class_ro_t) $8 = {
flags = 389
instanceStart = 40
instanceSize = 40
reserved = 0
ivarLayout = 0x0000000000000000 <no value available>
name = 0x0000000100000ef4 "Person"
baseMethodList = 0x00000001000010a0
baseProtocols = 0x0000000000000000
ivars = 0x0000000000000000
weakIvarLayout = 0x0000000000000000 <no value available>
baseProperties = 0x0000000000000000
_swiftMetadataInitializer_NEVER_USE = {}
}
(lldb) p $8.baseMethodList
(method_list_t *const) $9 = 0x00000001000010a0
(lldb) p *$9
(method_list_t) $10 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 26
count = 1
first = {
name = "walk"
types = 0x0000000100000f51 "v16@0:8"
imp = 0x0000000100000d00 (objc-debug`+[Person walk] at Person.m:13)
}
}
}
至此找到类方法walk 存在于元类中