Basic principles of iOS – Explore the nature of Class
Summary and record of video learning in the bottom class of small code brother. Part of the interview questions, through the analysis of the opposite questions to explore the essence of the content of the question. The following is a summary of the underlying principles of iOS – exploring the nature of OC objects
The nature of the Class
We know that both Class objects and metaclasses are of Class type. The underlying Class and mete-class are Pointers to the objc_class structure, which is the structure in memory. This chapter explores the nature of Class.
Class objectClass = [NSObject class];
Class objectMetaClass = object_getClass([NSObject class]);
Copy the code
Click on Class to get inside and we can find out
typedef struct objc_class *Class;
Copy the code
The Class object is actually a pointer to the objc_class structure. So we can say that a class object or metaclass object is actually an objC_class structure in memory.
If we go inside objc_class, we can see this code that often appears in the underlying principles.
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if ! __OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
Copy the code
This code is probably common in this article, but OBJC2_UNAVAILABLE; The code is no longer in use. So what is the current structure of objc_class? We look for the objC_class structure in objC source code.
We find that this structure inherits objc_Object and has some functions in it, because this is a C ++ structure, extended on C, so the structure can contain functions. Let’s go inside objc_Object and intercept some of the code
We find that objc_Object has an ISA pointer, so objc_class inherits objc_Object and also has an ISA pointer
So where is the information that we saw before, the information that’s stored in a class about the member variables, instance methods, property names, etc. So we go to class_rw_T, and we intercept some code, and we find that class_rw_T stores a list of methods, a list of properties, a list of protocols, and so on.
Class_rw_t is obtained by using bits to call the data method, which is implemented inside the data method. As you can see, the data function internally only operates on bits &FAST_DATA_MASK
The member variable information is stored inside class_ro_T, so we go to class_RO_T.
The final summary is summarized by a picture
How to prove the above is true.
We can customize a structure, and if the structure we write is the same as the real objC_class structure, then when we force the conversion, we will assign a one-to-one value. At this point we can get information from inside the structure.
The following code is a custom structure modeled after the objC_class structure by extracting the information needed to use it.
#import <Foundation/Foundation.h>
#ifndef XXClassInfo_h
#define XXClassInfo_h
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# endif
#if __LP64__
typedef uint32_t mask_t;
#else
typedef uint16_t mask_t;
#endif
typedef uintptr_t cache_key_t;
struct bucket_t {
cache_key_t _key;
IMP _imp;
};
struct cache_t {
bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
};
struct entsize_list_tt {
uint32_t entsizeAndFlags;
uint32_t count;
};
struct method_t {
SEL name;
const char *types;
IMP imp;
};
struct method_list_t : entsize_list_tt {
method_t first;
};
struct ivar_t {
int32_t *offset;
const char *name;
const char *type; uint32_t alignment_raw; uint32_t size; }; struct ivar_list_t : entsize_list_tt { ivar_t first; }; struct property_t { const char *name; const char *attributes; }; struct property_list_t : entsize_list_tt { property_t first; }; struct chained_property_list { chained_property_list *next; uint32_t count; property_t list[0]; }; typedef uintptr_t protocol_ref_t; struct protocol_list_t { uintptr_t count; protocol_ref_t list[0]; }; struct class_ro_t { uint32_t flags; uint32_t instanceStart; uint32_t instanceSize; // The memory space occupied by the instance object#ifdef __LP64__
uint32_t reserved;
#endifconst uint8_t * ivarLayout; const char * name; // Class name method_list_t * baseMethodList; protocol_list_t * baseProtocols; const ivar_list_t * ivars; // List of member variables const uint8_t * weakIvarLayout; property_list_t *baseProperties; }; struct class_rw_t { uint32_t flags; uint32_t version; const class_ro_t *ro; method_list_t * methods; // method list property_list_t *properties; Const protocol_list_t * protocols; // Protocol list Class firstSubclass; Class nextSiblingClass; char *demangledName; };#define FAST_DATA_MASK 0x00007ffffffffff8UL
struct class_data_bits_t {
uintptr_t bits;
public:
class_rw_t* data() {// provide the data() method for &fast_data_maskreturn(class_rw_t *)(bits & FAST_DATA_MASK); }}; Struct xx_objc_object {void *isa; }; Struct xx_objc_class: xx_objc_object {Class superclass; cache_t cache; class_data_bits_t bits; public: class_rw_t*data() {
return bits.data();
}
xx_objc_class* metaClass() {// Provide the metaClass function to get the metaClass objectreturn(xx_objc_class *)((long long)isa & ISA_MASK); }};#endif /* XXClassInfo_h */
Copy the code
Next we force our own class into our own simplified class structure type.
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "XXClassInfo.h"/* Person */ @interface Person : NSObject <NSCopying> { @public int _age; } @property (nonatomic, assign) int height; - (void)personMethod; + (void)personClassMethod; @end @implementation Person - (void)personMethod {} + (void)personClassMethod {} @end /* Student */ @interface Student : Person <NSCoding> { @public int _no; } @property (nonatomic, assign) int score; - (void)studentMethod; + (void)studentClassMethod; @end @implementation Student - (void)studentMethod {} + (void)studentClassMethod {} @end int main(int argc, const char * argv[]) { @autoreleasepool { NSObject *object = [[NSObject alloc] init]; Person *person = [[Person alloc] init]; Student *student = [[Student alloc] init]; xx_objc_class *objectClass = (__bridge xx_objc_class *)[object class]; xx_objc_class *personClass = (__bridge xx_objc_class *)[person class]; xx_objc_class *studentClass = (__bridge xx_objc_class *)[student class]; xx_objc_class *objectMetaClass = objectClass->metaClass(); xx_objc_class *personMetaClass = personClass->metaClass(); xx_objc_class *studentMetaClass = studentClass->metaClass(); class_rw_t *objectClassData = objectClass->data(); class_rw_t *personClassData = personClass->data(); class_rw_t *studentClassData = studentClass->data(); class_rw_t *objectMetaClassData = objectMetaClass->data(); class_rw_t *personMetaClassData = personMetaClass->data(); class_rw_t *studentMetaClassData = studentMetaClass->data(); // 0x00007ffffffffff8 NSLog(@"%p %p %p %p %p %p", objectClassData, personClassData, studentClassData,
objectMetaClassData, personMetaClassData, studentMetaClassData);
return 0;
}
Copy the code
We can see the information inside the class through the interrupt point.
At this point, we take out the classic graph again and analyze the isa pointer and superclass pointer in the graph one by one
The instance objects
First let’s look at the instance object. We learned from the previous article that the Instance object stores the ISA pointer and other member variables, and the ISA pointer of the instance object points to the address of its class object. ObjectClass, personClass, and studentClass are the three instance objects created in the above code.
From the above figure, we can see that the INSTANCE object does store the ISA pointer and its member variables, and the address calculated after the & operation of the ISA pointer of the instance object is indeed the memory address of its corresponding class object. Thus we prove that ISA, superclass, points to lines 1, 2 and 3 in the graph.
Class object
Then we look at the class object, also through the last article, we know that the class object stores isa pointer, superclass pointer, as well as the class attribute information, class member variables information, class object methods, and class protocol information. We know that this information is stored in the class_rw_T of the class object, and we spy on it by casting it. The following figure
In the figure above, we simulate calling the.data function on the Person object, which performs &fast_datA_mask (0x00007FFFFFFFF8ul) on bits and converts it to class_rw_t. PersonClassData in the figure above. We found that member variable information, object methods, attributes and other information only display the first. If you want to get more information, you need to move the pointer later through the code to obtain. InstaceSize = 16 corresponds to the isa pointer to the Person object (8 bytes +_age4 bytes +_height4 bytes). ObjectClassData and studentClassData are not analyzed here. The basic content is the same as personClassData.
Do isa and superclass Pointers in class objects point like the classic illustration? So let’s verify that.
By analyzing the memory address in the figure above, we prove that ISA, superclass, points to lines 4, 5, and 6 of the ISA pointer in the figure, and to lines 10, 11, and 12 of the Superclass pointer.
Meta – class object
The meta-class contains the isa pointer, the superclass pointer, and the class method information of the class. We also know that meta-class metaclasses have the same structure as class metaclasses, but store different information, and that the ISA pointer of the metaclasses points to the base metaclasses, and the ISA pointer of the base metaclasses points to itself. A superclass pointer to a metaclass object points to a metaclass object of its parent class, and a superclass pointer to a metaclass object of its base class points to an object of its class.
As with the class object, we mock the person metaclass by calling the.data function, which does &fast_data_mask (0x00007FFFFFFFF8ul) to bits and converts it to class_rw_t.
First, we can see that the structure is the same as personClassData, and the member variables and attribute lists are empty, while methods stores the class method personClassMethod.
Next, verify that the ISA and Superclass Pointers point to the same number as the above.
The isa pointer to the base class points to itself. The isa pointer to the base class points to itself.
The superclass of the meta-class refers to the superclass of the superclass, and the superclass of the base class refers to the class of the base class.
Recently saw a sentence, here with everyone mutual encouragement. It’s easier when you acknowledge your differences. Because we finally do not care about why he does I do not, finally do not silently strive to tell their hearts must be more than others. But also lost morale, lost the only chip to defeat others. The most afraid of a mediocre life, but also comfort their ordinary valuable.
Welcome to point out any mistakes in the article. I am XX_CC, a long grown but not enough of a guy.