One, memory offset
1. Study of ordinary pointer
int a = 10;
int b = 10;
int *a_p = &a;
int *b_p = &b;
NSLog(@"%d -- %p -- %p",a,&a,&a_p);
NSLog(@"%d -- %p -- %p",b,&b,&b_p);
// Output the result
202107 -26 - 16:15:17.348698+0800Memory offset [7982:190211] 10 -- 0x7ffee841a03c -- 0x7ffee841a030
202107 -26 - 16:15:17.348855+0800Memory offset [7982:190211] 10 -- 0x7ffee841a038 -- 0x7ffee841a028
Copy the code
- A and b both have values of 10 but a and B have different addresses
Copy the value
A and B belong toTwo copies of the data
- Address A is 0x7FFEE841A03C, address B is 0x7FFEE841A038 and the offset is 4, because a and B are
The int type
- The a_P address is 0x7FFEE841A030, and the B_P address is 0x7FFEE841A028. The offset is 8, because a_p,b_p is
Int * type
- Address size comparison: a > b > a_p > b_p, because they are local variables, they are stored
The stack area
!
2. Object pointer study
NBPerson *p1 = [NBPerson alloc];
NBPerson *p2 = [NBPerson alloc];
NBPerson *p3 = p2;
NSLog(@"---%@----%p",p1,&p1);
NSLog(@"---%@----%p",p2,&p2);
NSLog(@"---%@----%p",p3,&p3);
// Output the result
202107 -26 - 18:04:00.553396+0800Memory offset [10054:263449] ---<NBPerson: 0x6000012ac2e0>----0x7ffee47bb038
202107 -26 - 18:04:00.553507+0800Memory offset [10054:263449] ---<NBPerson: 0x6000012ac2f0>----0x7ffee47bb030
202107 -26 - 18:04:00.553599+0800Memory offset [10054:263449] ---<NBPerson: 0x6000012ac2f0>----0x7ffee47bb028
Copy the code
alloc
Open up internal existenceThe heap area
.A local variable
Open up internal existenceThe stack area
- The heap area
low
Address — — >high
Address, stack areahigh
Address — — >low
address - Both P3 and P2 store the address of the second alloc
Same data
3. Array pointer study
int c[4] = {1.2.3.4};
int *d = c;
NSLog(@"%p - %p - %p ",&c,&c[0],&c[1]);
NSLog(@"%p - %p - %p ",d,d+1,d+2);
for (int i = 0; i<4; i++) {
//(d+ I) take the value inside the address
int value = *(d+i);
NSLog(@"value = %d",value);
}
// Output the result
202107 -26 - 18:17:57.673897+0800Memory offset [10303:272382] 0x7ffeef40c040 - 0x7ffeef40c040 - 0x7ffeef40c044
202107 -26 - 18:17:57.674018+0800Memory offset [10303:272382] 0x7ffeef40c040 - 0x7ffeef40c044 - 0x7ffeef40c048
202107 -26 - 18:17:57.674109+0800Memory offset [10303:272382] value = 1
202107 -26 - 18:17:57.674187+0800Memory offset [10303:272382] value = 2
202107 -26 - 18:17:57.674255+0800Memory offset [10303:272382] value = 3
202107 -26 - 18:17:57.674330+0800Memory offset [10303:272382] value = 4
// the address of c is 7ffeef40C040
// The four elements of C are 7FFeEF40C040, 7FFeEF40C044, 7FFeEF40C048, 7FFeEF40C04c
Copy the code
- The address of an array is the element in the array
The first address
, i.e.,&c
and&c[0]
Are allThe first address
- Between each element of an array
Address space
Based on the current elementThe data type
Decision of the - The addresses of the elements of the array can be passed
The first address
+n
*The type size
In which the elements in the array must be of the same type. - Array elements are different
The first address
+The offset
Method, based on the offset value of the current variable (requires the addition of the previous type sizes)
Second, isa moves
- As you can see from the previous article, objects are essentially
The structure of the body
, the first member variable of the structure isisa
. And isa points to the current class, so why would Apple do that? Let’s explore
1. Apple’s official ISA bitmap
- We can probably see some patterns in this picture
- Non-root class (NSObject)
object
Isa points to the class,class
Isa to metaclass,The metaclass
Isa points to the root metaclass,A metaclass
Isa points to itself - Root class (NSObject)
object
Isa points to the root class,The root class
Isa points to the root metaclass,A metaclass
Isa points to itself - Non-root class (NSObject)
The metaclass of the parent class
isThe superclass of the metaclass
2. Number of class object memory
Class class1 = [NBPerson class];
Class class2 = [NBPerson alloc].class;
Class class3 = object_getClass([NBPerson alloc]);
Class class4 = [NBPerson alloc].class;
NSLog(@"\n-%p-\n-%p-\n-%p-\n-%p-",class1,class2,class3,class4);
// Output the result
202107 -27 - 10:19:47.940292+0800Memory offset [21711:526731]
-0x1021b5520-
-0x1021b5520-
-0x1021b5520-
-0x1021b5520-
Copy the code
Source code analysis: class object address is the same, each class in memory only a piece of memory, and ordinary object memory is not the same
-
In the previous article, there are three kinds of information to get the class, and using the mask to get the information is relatively fast and direct.
-
From the objC4 source code:
X86_64: define ISA_MASK0x00007ffffffffff8ULL arm64: define ISA_MASK0x0000000ffffffff8ULL ARM64 (Simulators) : Define ISA_MASK0x007ffffffffffff8ULL
Copy the code
3. Metaclass exploration
NBPerson *p1 = [[NBPerson alloc]init];
NSLog(@ "% @",p1);
Copy the code
- Breakpoint debugging
202107 -27 - 10:29:03.000337+0800Memory offset [21861:534807] <NBPerson: 0x6000009e0230>
(lldb) p/x p1
(NBPerson *) $0 = 0x00006000009e0230
(lldb) x/4gx 0x00006000009e0230// Object address
0x6000009e0230: 0x000000010c315520 0x0000000000000000
0x6000009e0240: 0x00001759aa2a0240 0x0000600000bc0026
// Find the class address through the object's ISA
(lldb) p/x 0x000000010c315520 & 0x007ffffffffffff8
(long) $1 = 0x000000010c315520
(lldb) po 0x000000010c315520
NBPerson
// Find the metaclass address through the isa of the class
(lldb) x/4gx 0x000000010c315520
0x10c315520: 0x000000010c3154f8 0x00007fff86d50660
0x10c315530: 0x00006000037ed200 0x000580100000000f
(lldb) p/x 0x000000010c3154f8 & 0x007ffffffffffff8
(long) $9 = 0x000000010c3154f8
(lldb) po 0x000000010c3154f8
NBPerson
Copy the code
- Breakpoint Process summary
- Through object
p1
isa0x000000010c315520
Find the address of the class0x000000010c315520
- Through the class
NBPerson
isa0x000000010c3154f8
Find the address of the metaclass0x000000010c3154f8
4, root metaclass derivation
- Continue the previous break point
// Metaclass isa finds root metaclass
(lldb) x/4gx 0x000000010c3154f8
0x10c3154f8: 0x00007fff86d50638 0x00007fff86d50638
0x10c315508: 0x00006000025e0700 0x0004c03100000007
(lldb) p/x 0x00007fff86d50638 & 0x007ffffffffffff8
(long) $11 = 0x00007fff86d50638
(lldb) po 0x00007fff86d50638
NSObject
// The root metaclass isa finds the root metaclass.
(lldb) x/4gx 0x00007fff86d50638
0x7fff86d50638: 0x00007fff86d50638 0x00007fff86d50660
0x7fff86d50648: 0x00006000037e8400 0x0009c0310000000f
(lldb) p/x 0x00007fff86d50638 & 0x007ffffffffffff8
(long) $13 = 0x00007fff86d50638
(lldb) po 0x00007fff86d50638
NSObject
Copy the code
- Breakpoint Process summary
The metaclass
Isa pointingA metaclass
- Root metaclass isa pointing to
oneself
MetaClass and rootMetaClass are the same as objc -> class -> metaClass -> rootMetaClass -> rootMetaClass in isa bitmap.
5. Class inheritance
Class tMetaClass = object_getClass(NBTeacher.class);/ / NBTeacher metaclass
Class tMetaSuperClass = class_getSuperclass(tMetaClass);// Superclass of the metaclass of NBTeacher
Class pMetaClass = object_getClass(NBPerson.class); / / NBPerson metaclass
Class pMeatSuperClass = class_getSuperclass(pMetaClass);// The parent class of the metaclass NBPerson
Class nMetaClass = object_getClass(NSObject.class);/ / NSObject metaclass
Class nSuperClass = class_getSuperclass(NSObject.class);/ / parent class NSObject
Class nMetaSuperClass = class_getSuperclass(nMetaClass);// Superclass of NSObject's metaclass
NSLog(@"NBTeacher-%p",NBTeacher.class);
NSLog(@"NBPerson-%p",NBPerson.class);
NSLog(@"NSObject-%p".NSObject.class);
NSLog(@"%@ - %p - %@ - %p",tMetaClass,tMetaClass,tMetaSuperClass,tMetaSuperClass);
NSLog(@"%@ - %p - %@ - %p",pMetaClass,pMetaClass,pMeatSuperClass,pMeatSuperClass);
NSLog(@"%@ - %p - %@ - %p",nMetaClass,nMetaClass,nMetaSuperClass,nMetaSuperClass);
NSLog(@"%@ - %p",nSuperClass,nSuperClass);
Copy the code
- The output
202107 -27 - 16:59:36.204223+0800Memory offset [29797:756093] NBTeacher-0x10f015620
202107 -27 - 16:59:36.204689+0800Memory offset [29797:756093] NBPerson-0x10f0155d0
202107 -27 - 16:59:36.204782+0800Memory offset [29797:756093] NSObject-0x7fff86d50660
202107 -27 - 16:59:36.204917+0800Memory offset [29797:756093] NBTeacher - 0x10f0155f8 - NBPerson - 0x10f0155a8
202107 -27 - 16:59:36.205001+0800Memory offset [29797:756093] NBPerson - 0x10f0155a8 - NSObject - 0x7fff86d50638
202107 -27 - 16:59:36.205082+0800Memory offset [29797:756093] NSObject - 0x7fff86d50638 - NSObject - 0x7fff86d50660
202107 -27 - 16:59:36.205176+0800Memory offset [29797:756093] (null) - 0x0
Copy the code
NBTeacher is the parent class of the metaclass
andNBPerson metaclass
Is the sameThe parent class of the NBPerson metaclass
andNSObject metaclass
Is the sameNBTeacher
inheritanceNBPerson
.NBPerson
inheritanceNSObject
.NSObject
Is the parent classnil
NBTeacher
Yuan class inheritanceNBPerson
Metaclasses,NBPerson
inheritanceA metaclass
.A metaclass
inheritanceNSObject
Third, class structure analysis
Look at objc4(version 818) source, objc-Runtimenew.h, and find objc_class structure as follows:
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
Class getSuperclass() const {
#if __has_feature(ptrauth_calls)
# if ISA_SIGNING_AUTH_MODE == ISA_SIGNING_AUTH
if (superclass == Nil)
return Nil;
#if SUPERCLASS_SIGNING_TREAT_UNSIGNED_AS_NIL
void *stripped = ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
if ((void *)superclass == stripped) {
void *resigned = ptrauth_sign_unauthenticated(stripped, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
if ((void*)superclass ! = resigned)return Nil;
}
#endif
void *result = ptrauth_auth_data((void *)superclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
return (Class)result;
# else
return (Class)ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
# endif
#else
return superclass;
#endif
}
Copy the code
- Source code analysis
objc_class
inheritanceobjc_object
.objc_object
There’s only one member variableisa
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
Copy the code
-
There is also a hidden ISA in the structure of the class, which takes 8 bytes
-
Class superClass is the parent Class of the Class. The pointer to the structure takes 8 bytes
-
Cache_t cache is the cache space of the class and takes up 16 bytes
-
Class_data_bits_t stores class data, such as attributes, methods, and so on.
1, explore the size of cache_t
- Search for struct cache_t and find it
struct cache_t {
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask;/ / 8 bytes
union {
struct {
explicit_atomic<mask_t> _maybeMask;/ / 4 bytes
#if __LP64__
uint16_t _flags;//2 bytes objc2 go this way
#endif
uint16_t _occupied;/ / 2 bytes
};
explicit_atomic<preopt_cache_t *> _originalPreoptCache;/ / 8 bytes
};
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
// _bucketsAndMaybeMask is a buckets_t pointer
// _maybeMask is the buckets mask
static constexpr uintptr_t bucketsMask = ~0ul; static_assert(! CONFIG_USE_PREOPT_CACHES,"preoptimized caches not supported");
/ /... Ignore code that has nothing to do with the structure
// The source code is located on lines 338-550 of the objc-runtime-new.h file
Copy the code
typedef unsigned long uintptr_t
It is an unsigned integer of 8 bytes.preopt_cache_t *
Is a pointer to a structure and takes 8 bytes.uint16_t
It is an unsigned 16-bit integer, occupying 2 bytes.- Mask_t is
uint32_t
Type, takes 4 bytes. - Cache_t has the following memory size:
Uintptr_t Memory size 8 bytes
+The union memory size is 8 bytes
=16 bytes
so
isa
The memory address isThe first address
superclass
Address isThe first address
+0x08
cache_t
Address isThe first address
+0x10
bits
Address isThe first address
+0x20
2. Class_data_bits_t bits structure
The class_datA_BITS_t bits structure records the attributes, member variables, and methods of a class. So you have to know what’s in the structure, class_data_bits
struct class_data_bits_t {
friend objc_class;
// Values are the FAST_ flags above.
uintptr_t bits;
private:
bool getBit(uintptr_t bit) const
{
return bits & bit;
}
// Atomically set the bits in `set` and clear the bits in `clear`.
// set and clear must not overlap.
void setAndClearBits(uintptr_t set, uintptr_t clear)
{
ASSERT((set & clear) == 0);
uintptr_t newBits, oldBits = LoadExclusive(&bits);
// Omit part of the code here
public:
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
void setData(class_rw_t *newData)
{
// Omit part of the code here
Copy the code
- Class_rw_t source
struct class_rw_t { // Be warned that Symbolication knows the layout of this structure. uint32_t flags; uint16_t witness; #if SUPPORT_INDEXED_ISA uint16_t index; #endif explicit_atomic<uintptr_t> ro_or_rw_ext; Class firstSubclass; Class nextSiblingClass; private: using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t, class_rw_ext_t, PTRAUTH_STR("class_ro_t"), PTRAUTH_STR("class_rw_ext_t")>; const ro_or_rw_ext_t get_ro_or_rwe() const { return ro_or_rw_ext_t{ro_or_rw_ext}; } void set_ro_or_rwe(const class_ro_t *ro) { ro_or_rw_ext_t{ro, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_relaxed); } 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); } class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false); public: void setFlags(uint32_t set) { __c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED); } void clearFlags(uint32_t clear) { __c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED); } // 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)); } class_rw_ext_t *ext() const { return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext); } class_rw_ext_t *extAllocIfNeeded() { auto v = get_ro_or_rwe(); if (fastpath(v.is<class_rw_ext_t *>())) { return v.get<class_rw_ext_t *>(&ro_or_rw_ext); } else { return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext)); } } class_rw_ext_t *deepCopy(const class_ro_t *ro) { return extAlloc(ro, true); } const class_ro_t *ro() const { auto v = get_ro_or_rwe(); if (slowpath(v.is<class_rw_ext_t *>())) { return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro; } return v.get<const class_ro_t *>(&ro_or_rw_ext); } void set_ro(const class_ro_t *ro) { auto v = get_ro_or_rwe(); if (v.is<class_rw_ext_t *>()) { v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro = ro; } else { set_ro_or_rwe(ro); } } const method_array_t methods() const { auto v = get_ro_or_rwe(); if (v.is<class_rw_ext_t *>()) { return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods; } else { return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()}; } } const property_array_t properties() const { auto v = get_ro_or_rwe(); if (v.is<class_rw_ext_t *>()) { return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties; } else { return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties}; } } const protocol_array_t protocols() const { auto v = get_ro_or_rwe(); if (v.is<class_rw_ext_t *>()) { return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols; } else { return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols}; }}};Copy the code
class_rw_t
Is a structure type that providesGet the property list
.Methods list
.Agreement list
Methods. Verify methods, properties, and variables by instanceclass_rw_t
To add attributes and methods and member variables to the class, follow the validation process.
3. Obtain member variables and class methods
- New NBPerson
@interface NBPerson : NSObject{
double height;
}
@property(nonatomic.copy)NSString *name;
@property(nonatomic.copy)NSString*nickName; - (void)sayHello; + (void)sayNB;
@end
@implementation NBPerson- (void)sayHello{
NSLog(@"hello----"); } + (void)sayNB{
NSLog(@"NB----");
}
@end
Copy the code
- run
NBPerson *nb = [NBPerson alloc];
nb.name = @"nb";
nb.nickName = @"nickeName";
Copy the code
- Breakpoint debugging
(lldb) p/x NBPerson.class / / the current class
(Class) $4 = 0x0000000100008268 NBPerson
(lldb) p/x 0x0000000100008268 + 0x20 / / address bits
(long) $5 = 0x0000000100008288
(lldb) p (class_data_bits_t *)0x0000000100008288
(class_data_bits_t *) $6 = 0x0000000100008288
(lldb) p $6->data() // Get class_ro_t
(class_rw_t *) $7 = 0x0000000101315fb0
(lldb) p $7->properties() / / to find
(const property_array_t) $8 = {
list_array_tt<property_t, property_list_t, RawPtr> = {
= {
list = {
ptr = 0x00000001000081e8
}
arrayAndFlag = 4295000552
}
}
}
(lldb) p $8.list
(const RawPtr<property_list_t>) $9 = {
ptr = 0x00000001000081e8
}
(lldb) p $9.ptr // Find the property list address
(property_list_t *const) $10 = 0x00000001000081e8
(lldb) p *$10 // Get the property list data
(property_list_t) $11 = {
entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
(lldb) p $11.get(0)// Find the first attribute
(property_t) $12 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb) p $11.get(1)// Find the second attribute
(property_t) $13 = (name = "nickName", attributes = "T@\"NSString\",C,N,V_nickName")
(lldb) p $11.get(2)// No third attribute array is out of boundsAn Assertion failed: (I < count), the function of get the file/Users/xiaozhongwang/Desktop/file summary/iOS/objc4_debug - master/objc4818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb)
Copy the code
-
You can find the name attribute and nickname attribute
-
Height member variable not found
-
Where did the height go? Then find a
-
In addition to properties, methods, and protocols in class_rw_t, there is also a class_ro_t structure pointer type ro(),
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
union {
const uint8_t * ivarLayout;
Class nonMetaclass;
};
explicit_atomic<const char *> name;
// With ptrauth, this is signed if it points to a small list, but
// may be unsigned if it points to a big list.
void *baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
Copy the code
- Follow the debugging above
lldb) p $7->ro()
(const class_ro_t *) $18 = 0x00000001000080a0
(lldb) p $18.ivars
(const ivar_list_t *const) $19 = 0x0000000100008180
Fix-it applied, fixed expression was:
$18->ivars
(lldb) p *$19
(const ivar_list_t) $20 = {
entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 3)
}
(lldb) p $20.get(0)
(ivar_t) $21 = {
offset = 0x0000000100008228
name = 0x0000000100003ecf "height"
type = 0x0000000100003f29 "d"
alignment_raw = 3
size = 8
}
(lldb) p $20.get(1)
(ivar_t) $22 = {
offset = 0x0000000100008230
name = 0x0000000100003ed6 "_name"
type = 0x0000000100003f2b "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $20.get(2)
(ivar_t) $23 = {
offset = 0x0000000100008238
name = 0x0000000100003edc "_nickName"
type = 0x0000000100003f2b "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $20.get(3)// The array is out of boundsAn Assertion failed: (I < count), the function of get the file/Users/xiaozhongwang/Desktop/file summary/iOS/objc4_debug - master/objc4818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb)
Copy the code
conclusion
-
Find the height member variable and the _name,_nickNmae member variable
-
The underlying implementation of member variables is iVAR_t, which is stored in the class_ro_t member variable list
-
The system automatically adds _ attribute name variables to the attributes, stored in the class_ro_t member variable list
-
Methods to explore
(lldb) p $7->methods()
(const method_array_t) $24 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x00000001000080e8
}
arrayAndFlag = 4295000296
}
}
}
(lldb) p $24.list
(const method_list_t_authed_ptr<method_list_t>) $25 = {
ptr = 0x00000001000080e8
}
(lldb) p $25.ptr
(method_list_t *const) $26 = 0x00000001000080e8
(lldb) p *$26
(method_list_t) $27 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 6)
}
(lldb) p $27.get(0).big()
(method_t::big) $28 = {
name = "sayHello"
types = 0x0000000100003f21 "v16@0:8"
imp = 0x0000000100003c90 (KCObjcBuild`-[NBPerson sayHello] at main.m:31)
}
(lldb) p $27.get(1).big()
(method_t::big) $29 = {
name = "name"
types = 0x0000000100003f37 "@ @ 0:8 16"
imp = 0x0000000100003cc0 (KCObjcBuild`-[NBPerson name] at main.m:20)}Copy the code
-
Object methods are stored in the method list method_list_t in the NBPerson class
-
The class method is not in the method list of NBPerson, method_list_t. Where are the class methods?
Found usingget(index)
The way is not available to useget(index).big()
To get it. Why is that?
Explore property_t and method_t
struct property_t { const char *name; const char *attributes; }; struct method_t { struct big { SEL name; const char *types; MethodListIMP imp; }; big &big() const { ASSERT(! isSmall()); return *(struct big *)this; } SEL name() const { if (isSmall()) { return (small().inSharedCache() ? (SEL)small().name.get() : *(SEL *)small().name.get()); } else { return big().name; } } const char *types() const { return isSmall() ? small().types.get() : big().types; } IMP imp(bool needsLock) const { if (isSmall()) { IMP imp = remappedImp(needsLock); if (! imp) imp = ptrauth_sign_unauthenticated(small().imp.get(), ptrauth_key_function_pointer, 0); return imp; } return big().imp; }Copy the code
attribute
The underlying implementation isproperty_t
In theproperty_t
Structure is defined inname
Variables such asmethods
The underlying implementation ismethod_t
In themethod_t
Structure defined in thebig()
Through thebig()
To obtainSEL
andIMP
Continue to find methods
(lldb) p $27.get(2).big()
(method_t::big) $31 = {
name = ".cxx_destruct"
types = 0x0000000100003f21 "v16@0:8"
imp = 0x0000000100003d80 (KCObjcBuild`-[NBPerson .cxx_destruct] at main.m:29)
}
(lldb) p $27.get(3).big()
(method_t::big) $32 = {
name = "setName:"
types = 0x0000000100003f3f "v24@0:8@16"
imp = 0x0000000100003cf0 (KCObjcBuild`-[NBPerson setName:] at main.m:20)
}
(lldb) p $27.get(4).big()
(method_t::big) $33 = {
name = "nickName"
types = 0x0000000100003f37 "@ @ 0:8 16"
imp = 0x0000000100003d20 (KCObjcBuild`-[NBPerson nickName] at main.m:21)
}
(lldb) p $27.get(5).big()
(method_t::big) $34 = {
name = "setNickName:"
types = 0x0000000100003f3f "v24@0:8@16"
imp = 0x0000000100003d50 (KCObjcBuild`-[NBPerson setNickName:] at main.m:21)
}
(lldb) p $27.get(6). The big () an Assertion failed: (I < count), the function of get the file/Users/xiaozhongwang/Desktop/file summary/iOS/objc4_debug - master/objc4818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb)
Copy the code
method_list_t
There areObject methods
, the properties of theA setter method
andGetter method
method_list_t
Is not obtained inClass method
To explore the metaclass
(lldb) p/x object_getClass(NBPerson.class)
(Class) $0 = 0x0000000100008240
(lldb) p/x 0x0000000100008240 + 0x20
(long) $1 = 0x0000000100008260
(lldb) p (class_data_bits_t*)0x0000000100008260
(class_data_bits_t *) $2 = 0x0000000100008260
(lldb) p $2->data()
(class_rw_t *) $3 = 0x0000000100627d70
(lldb) p $3->methods()
(const method_array_t) $4 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x0000000100008080
}
arrayAndFlag = 4295000192
}
}
}
(lldb) p $4.list.ptr
(method_list_t *const) $5 = 0x0000000100008080
(lldb) p * $5
(method_list_t) $6 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 1)
}
(lldb) p $6.get(0).big()
(method_t::big) $7 = {
name = "sayNB"
types = 0x0000000100003f21 "v16@0:8"
imp = 0x0000000100003c60 (KCObjcBuild`+[NBPerson sayNB] at main.m:34)}Copy the code
-
Find sayNB in the metaclass
-
Object_getClass gets the metaclass of JCPerson
-
Class methods are stored in the metaclasses method_list_t
Conclusion:
-
Class structure is mainly composed of isa, superclass, cache, composed of bits
-
Bits store attributes, methods, and protocols
-
Properties are stored in property_list_t, and member variables are stored in class_ro_t–> iVAR_list_T. The _ property name variable automatically generated by the system for the property is also stored in class_ro_t–> iVAR_list_t
-
Methods are stored in method_list_t, which mainly stores object methods, setter and getter methods for properties, and class methods are stored in the metaclass method_list_t