Objective-C Object Model and Application
This article mainly introduces the implementation details of the Objective-C object model and the support for isa swizzling and method swizzling in the Objective-C object model. I hope this article will help you better understand Objective-C objects.
ISA pointer
Objective-C is an object-oriented programming language. Every object is an instance of a class. In Objective-C, each object has a pointer named isa pointing to the class of the object. Each class describes the characteristics of a series of its instances, including the list of member variables and the list of member functions. Each object can receive messages, and the list of messages that the object can receive is saved in its corresponding class.
Press Shift + Command + O in XCode, and then enter NSObject. h and objc. h. You can open the NSObject definition header file. Through the header file, we can see that NSObject is a struct containing the isa pointer, as shown in:
According to the design principles of object-oriented language, everything should be an object (strictly speaking, Objective-C does not fully implement this because it has simple variable types such as int and double ). In Objective-C, every class is actually an object. Each class also has a pointer named isa. Each class can also accept messages. For example, [NSObject alloc] sends a message named alloc to the NSObject class.
Press Shift + Command + O in XCode and enter runtime. h to open the Class definition header file. We can see through the header file that the Class is also a struct containing the isa pointer, as shown in. (In the figure, there are other member variables besides isa, but they are used to be compatible with the legacy logic of Objective-C in non-Version 2.0. You can ignore this variable .)
Because a class is an object, it must also be a real column of another class. This class is metaclass ). The metadata class saves the list of class methods. When a class method is called, The Meta class first checks whether it has the implementation of this class method. If not, the Meta class searches for this method from its parent class, until the inheritance chain header is found.
Metaclass is also an object. Where does the isa pointer of the metaclass point? To be fully designed, the isa pointer of all metaclass points to a root metaclass ). The isa pointer of the root metaclass itself points to itself, thus forming a closed loop. As mentioned above, the list of messages that an object can receive is saved in the corresponding class. In actual programming, we almost never encounter the situation of sending messages to the Meta class, so its isa pointer is rarely used in reality. However, this design ensures that object orientation is clean, that is, everything is an object and there is an isa pointer.
Let's take a look at the inheritance relationship. Because the class method is defined in metaclass, and the method calling rule is that if this class does not have a method implementation, to its parent class. Therefore, to ensure that the class method of the parent class can be called in the subclass, the Meta class of the subclass will inherit the Meta class of the parent class. In other words, class objects and metadata objects have the same inheritance relationship.
I would like to clarify the relationship, but this part is indeed a bit difficult. The figure below may make the relationship between isa and inheritance clearer.
In this figure, the most confusing thing is the Root Class. In implementation, the Root Class refers to NSObject. We can see that:
- The NSObject class includes its object instance method.
- The NSObject metadata includes its class methods, such as the alloc method.
- The NSObject metadata class inherits from the NSObject class.
- The methods in an NSObject class are also found by NSObject subclass during method search. Class member variables
If you think of an instance of the class as a structure (struct) of C language, the isa pointer mentioned above is the first member variable of the structure, and other member variables of the class are arranged in the structure in sequence. Shows the order (picture from iOS 6 Programming Pushing the Limits):
To verify this statement, we create a new project in XCode and run the following code in main. m:
#import
@interface Father : NSObject { int _father;}@end@implementation Father@end@interface Child : Father { int _child;}@end@implementation Child@endint main(int argc, char * argv[]){ Child * child = [[Child alloc] init]; @autoreleasepool { // ... }}
We will place the breakpoint at @ autoreleasepool and enter p * child in the Console. Then we can see that Xcode outputs the following content, which is consistent with the above statement.
(lldb) p *child(Child) $0 = { (Father) Father = { (NSObject) NSObject = { (Class) isa = Child } (int) _father = 0 } (int) _child = 0}
Variable and immutableBecause the object layout in the memory can be regarded as a struct, the size of the struct cannot be changed dynamically. Therefore, the member variables cannot be dynamically added to the object at runtime.
The method definitions of objects are stored in the Variable Area of the class. Objective-C 2.0 is not exposed in the header file, but in Objective-C 1.0, we can see that the definition list of a method is a pointer named methodLists (as shown in ). By modifying the pointer value to which the Pointer Points, You can dynamically add member methods to a class. This is also the principle of Category implementation. It also explains why Category can only add member methods for objects, but cannot add member variables.
Note that the objc_setAssociatedObject and objc_getAssociatedObject methods can be used to add member variables to objects in disguise. However, because of the different implementation mechanisms, the object's memory structure is not actually changed.
In addition to the object method, isa itself is also a pointer, so we can dynamically modify the isa pointer value at runtime to replace the entire object behavior. However, this application scenario is rare.
System related API and application isa swizzlingThe implementation of KVO provided by the system uses the technology of dynamically modifying the value of the isa pointer. You can see the following description in Apple's document:
Key-Value Observing Implementation Details
Automatic key-value observing is implemented using a technique called isa-swizzling.
The isa pointer, as the name suggests, points to the object's class which maintains a dispatch table. This dispatch table essential tially contains pointers to the methods the class implements, among other data.
When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. as a result the value of the isa pointer does not necessarily reflect the actual class of the instance.
You shoshould never rely on the isa pointer to determine class membership. Instead, you shoshould use the class method to determine the class of an object instance.
Method Swizzling API descriptionObjective-C provides the following APIs to dynamically Replace the implementation of class methods or instance methods: