This article, the eighth in the Objective-C series, focuses on the underlying structure of OC objects and their classification: instance objects, class objects, and metaclass objects.
- Objective C (7) Object memory analysis
- Objective C (8) The nature and classification of objects
- Objective-c (9) KVC and KVO
- Objective-c (10) Category
- Objective-c load and Initialize
- Objective-c (12) Associative objects
After the objective-C (7) object memory analysis, we learned that a class is stored in memory.
However, we only analyzed the member variables and attributes of the class. We know that an OC object also includes extremely important information such as methods and protocols. So where are they, how are they stored and how are they used?
This paper further analyzes the classification of Objective-C class system and its complete distribution in memory.
To this end, we need to do some preparatory work first.
A, preparation,
1.1 Object Classification
Objective-c objects, OC objects for short, fall into three main categories:
-
Instance object (instance object)
-
Class object (Class object)
-
Meta-class objects (metaclass objects)
We conducted tests on three types of objects in OC, and the test results are as follows:
From the above figure, we can draw the following conclusions:
- There can be more than one instance object: for each alloc object, one instance object is created;
- There can be only one class object: the class object of different instance objects is the same;
- There can be only one metaclass object: there can be only one metaclass object for different instance objects (class objects);
So test code in a few methods, the following is also briefly described, part of the source code project -BFOCClass classification -01.
1.1.1 [NSObject class]
Mm: in NSObject.
+ (Class)class {
return self;
}
Copy the code
Returns the class object (metaclass object) itself.
So, [[[NSObject Class] class] returns an NSObject class object no matter how many times class is called.
1.1.2 [person1 class]
Returns the class object of the instance object
- (Class)class {
return object_getClass(self);
}
Copy the code
According to (2),
- [person1 class] : returns the object that isa points to in person1, which is the BFPerson class object;
1.1.3 objc_getClass
This method is very similar to object_getClass in terms of the method name.
- Parameter: string class name;
- Returns: the corresponding class object.
Class objc_getClass(const char *aClassName)
{
if(! aClassName)return Nil;
// NO unconnected, YES class handler
return look_up_class(aClassName, NO.YES);
}
Copy the code
1.1.4 object_getClass
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
Copy the code
Return the object referred to by isa in the passed obj. The passed obJ may be an instance object, a class object, or a meta-class object
The return value corresponds to:
A) If it is instance, return the class object
B) If it is a class object, return meta-class object
C) If it is a meta-class object, return the meta-class object of NSObject
So in the above test:
-
Object_getClass (person1) : returns the class object;
-
Object_getClass (personClass5) : returns a meta-class object;
1.1.5 class_isMetaClass
Returns whether it is a meta-class object.
1.2 Some constructs from source code
We will extract some of the structure from the source code for the rest of the argument.
1.2.1 NSObject
NSObject is derived from the source code, and its first member variable is isa. The Class structure’s first member variable name is also ISA.
Isa contains the address where the (meta) class information is stored.
1.2.2 class_rw_t
Class_rw_t and class_ro_t are structures that store class information, including member variables, attribute list, protocol list, and method list. The details are as follows:
Currently, we class_ro_t the properties, methods, and protocols that are determined at compile time for the current class.
Class_rw_t is where, at runtime, the Runtime reloads the attributes, methods, protocols, and so on of the current class layout.
1.2.3 method_t
method_t
Is the lowest level structure of a method.method_list_t
- List of methods, one-dimensional array
- The internal storage
method_t
class_ro_t
A member variable in.
method_array_t
- Again, it’s a list of methods, but it’s a two-dimensional array
- The internal storage
method_t
class_rw_t
Member variables in;
The relationship among the three is as follows:
Property and protocol are similar.
Why there are one – and two-dimensional arrays will be discussed in more detail in a future article.
1.property_t
The structure of property_array_t and property_list_t is similar to the array of method above. They are two-dimensional and one-dimensional arrays respectively.
struct property_t {
const char *name; / / the property name
const char *attributes; // A string indicating the properties of the property
};
Copy the code
If the attribute name is NAME and the type is NSString, the corresponding attributes are: T@”NSString”,C,N,V_name
1.2.5 protocol_t
Protocol_array_t and protocol_list_t are two and one dimensional arrays of protocol_T, respectively.
Similarly, we look at the protocol_t structure:
struct protocol_t : objc_object {
const char *mangledName;
struct protocol_list_t *protocols;
method_list_t *instanceMethods;
method_list_t *classMethods;
method_list_t *optionalInstanceMethods;
method_list_t *optionalClassMethods;
property_list_t *instanceProperties;
uint32_t size; // sizeof(protocol_t)
uint32_t flags;
// Fields below this point are not always present on disk.
const char **_extendedMethodTypes;
const char *_demangledName;
property_list_t *_classProperties;
};
Copy the code
1.2.6 ivar_t
We find that for member variables, there is only ivar_list_t, not ivar_array_t.
From this we can see that even the Runtime cannot add a member variable to a class at runtime.
struct ivar_t {
int32_t *offset;
const char *name;
const char *type;
// alignment is sometimes -1; use alignment() instead
uint32_t alignment_raw;
uint32_t size;
};
Copy the code
1.3 Memory of the NSObject instance object
We are already familiar with the memory structure of the NSObject instance object. Let’s elaborate on the following points:
- NSObject instance object has one and only one variable in memory called ISA, and ISA points to NSObject’s class object;
Here, for compile-time ISA, combined with the source code, we get the following:
Runtime ISA:
Memory storage of objects
Above, we did some preparatory work to see how and where NSObject stores the various structures of information.
Now we’re going to make a brief description of the three types.
2.1 the instance objects
Its memory layout is as follows:
The instance object stores information in memory:
isa
Pointer to the- Other member variables
2.2 class object
Class objects store information in memory mainly including
isa
Pointer to thesuperclass
Pointer to the- Class instance method information
- Class property information
- Class protocol information (Protocol)
- Class member variable information (IVAR)
2.3 meta – class object
Meta-class objects have the same memory structure as class objects, but their purpose is different. The information stored in the memory mainly includes
isa
Pointer to thesuperclass
Pointer to the- Class method information of a class
- Other values including attributes, protocols, and member variables are NULL
Isa and Superclass
Isa is rarely used in normal development, but I believe many iOS developers are familiar with it.
After learning about NSObject, structures, and objects, Apple provided Cocoa/Cocoa Touch with two Pointers to build a class system: ISA and Superclass. So how do you connect them in series?
Horizontal association: ISA establishes a horizontal association between instance objects, class objects, and meta-class objects of a class to provide guidance for searching for various types of information stored in objects.
Vertical connection: Superclass is the embodiment of inheritance, the most important feature in object-oriented languages. It embodies the relationships between classes, that is, it establishes vertical connections in class diagrams.
Note the distinction: relationships between objects of a class, and relationships between different classes!
3.1 the isa
3.1.1 isa pointer
3.1.2 ISA_MASK
To verify this conclusion, we run project-bfocClass class-01 on the real machine and try to get the BFPerson object and print the relevant address of the class:
BFPerson instance - 0x12fd1f570 0x12fd366e0
BFPerson class - 0x100091e28 0x100091e28 0x100091e28 0x100091e28 0x100091e28 0
BFPerson meta class - 0x100091e00 1 0x100091e28 0
(lldb) x/2xw 0x12fd1f570
0x12fd1f570: 0x00091e2d 0x000001a1
Copy the code
From the print we know:
- The address of the person1 instance object is 0x12FD1f570
- The first eight bytes of the address of the person1 object are
isa
, here is:0x1a100091e2d - The BFPerson Class address is 0x100091e28, which is different from 0x1A100091e2D
- 0x1a100091e2d(
isa
) & 0x0000000ffffffff8(ISA_MASK
) = 0x100091e28
3.2 superclass
3.2.1 class object
3.2.2 meta – class object
3.3 Class diagram system
With this in mind, ISA and SuperClass have teamed up to weave the following class diagram:
3.3.1 contact
-
Isa to
- The instance of
isa
Point to the class - A class of
isa
Pointing to the meta – class - Meta – class
isa
Meta-class that points to the base class
- The instance of
-
Superclass point to
- A class of
superclass
If a class that points to a parent class does not have a parent class,superclass
A pointer to nil - Meta – class
superclass
Meta-class that points to the parent classMeta-class of the base classsuperclass
Class that points to the base class
- A class of
3.3.2 Method Invocation
- Instance calls the path of an object method
isa
Find class, method does not exist, passsuperclass
To find the parent class - Class calls the trace of a class method
isa
Find meta-class, method does not exist, passsuperclass
To find the parent class
Code reference BFOCClass classification -01
Inheritance: BFStudent->BFPerson->NSObject
3.3.2.1 case 1
BFStudent *stu = [[BFStudent alloc] init];
[stu test];
Copy the code
-
BFStudent implementation – (void) test; , call BFStudent implementation method;
-
BFStudent not implemented -(void)test; , if BFPerson implementation, call BFPerson implementation;
-
BFStudent and BFPerson are not implemented. If NSObject is implemented, call NSObject.
-
[stu test] [stu test] [stu test] , will compile error, need to change the call method:
((* *void(*) (* * * *id**, **SEL**))objc_msgSend)(stu, **@selector**(test)); Copy the code
- If NSObject implementation
+(void)test;
The collapse; - If NSObject implementation
-(void)test;
, the call-(void)test;
;
- If NSObject implementation
-
-
[BFStudent test]: unrecognized selector sent to instance
3.3.2.2 case 2
[BFStudent test];
Copy the code
-
BFStudent implementation + (void) test; , the implementation of calling BFStudent;
-
BFStudent not implement +(void)test; , if BFPerson implementation, call BFPerson implementation;
-
BFStudent and BFPerson are not implemented. NSObject is called.
-
Unable to [BFStudent test]; Call, the call method should be changed to:
Class stuClass = [BFStudent class]; ((void(*) (id, SEL))objc_msgSend)(stuClass, @selector(test)) Copy the code
- If NSObject implementation
+(void)test;
, the call+(void)test;
; - If NSObject implementation
-(void)test;
, the call-(void)test;
; - If NSObject implementation
+(void)test;
and-(void)test;
, the call+(void)test;
;
- If NSObject implementation
-
-
+[BFStudent test]: unrecognized selector sent to instance
3.3.3 analysis
In case 1 and case 2, we can understand most of this, but there is one case. There is a difference.
When neither BFStudent nor BFPerson implements the corresponding object method (class method), they look in NSObject.
- Object method: NSObject looks for the corresponding object method, fails to find the object method, crashes, see the blue arrow below.
- Class method: NSObject looks for the corresponding class method, does not find the corresponding class method, and then looks for the corresponding instance method. If neither is found, it crashes, as shown in the yellow arrow below.
4. The complete internal structure of the object
At this point, we’re pretty much done with the object, but we still haven’t looked at the entire internal structure of the object at runtime.
4.1 How To Snoop
There are two ways:
- Method 1: compile objC source code, directly throughobjc4Source code debugging;
- For compilation details, please refer to Runtime
- Method two: abstract [some from the source structure](#2. Some from the source structure) mentioned in the structure, the normal object into the corresponding structure, debugging;
Let’s do method two.
4.2 Find out
-
The abstracted structure can be downloaded here.
-
After the import, adjust the compile project to the command line project and change main.m to main.mm to support C++ compilation.
Corresponding project source code.
2 class object
4.2.2 Metaclass objects
Now, do you know the nature of OC objects? How are they classified?
reference
link
- objc4
- Runtime (a) Introduction to Runtime
The sample code
- This article source project –BFOCClass classification – 01
- This article source project –BFOCClass classification – 02