Preface
Original article. For more information, see Tang Qiao's technical blog.
This article mainly introduces the implementation details of the Objective-C object model andisa swizzling
Andmethod swizzling
. 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.
PressShift + Command + O
Input NSObject. h and objc. h to open the NSObject definition header file. We can see through the header file 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, such[NSObject alloc]
Is to send the name to the NSObject classalloc
Message.
PressShift + Command + O
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 a metadata class (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.
Metadata (metaclass
) Is also an object, so where does the isa pointer of the Meta class point? For the sake of design integrity, the isa pointer of all meta classes will point to a root Meta class (rootmetaclass
). 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 definition is saved in the Meta class (metaclass
), And the method calling rule is that if the class does not have a method implementation, it continues to search for 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 give you a clearer picture of the relationship between isa and inheritance (this picture is from here)
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:
12345678910111213141516171819202122232425262728293031 |
#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 place the breakpoint under@autoreleasepool
And enterp *child
, You can see that Xcode outputs the following content, which is consistent with the above statement.
12345678910 |
(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 namedmethodLists
As shown in ). By modifying the pointer value to which the Pointer Points, You can dynamically add member methods to a class. This is alsoCategory
Implementation principle. It also explains whyCategory
Only member methods can be added for objects, but member variables cannot be added.
Please note thatobjc_setAssociatedObject
Andobjc_getAssociatedObject
The method can add member variables to an object in disguise. However, because the implementation mechanism is different, it does not actually change the memory structure of the object.
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.
Similarly, Key-Value Coding (KVC) provided by the system is also used in isa swizzling technology ).(Thank you for pointing out the error. KVC does not use isa swizzling)
Method Swizzling API descriptionObjective-C provides the following APIs to dynamically Replace the implementation of class methods or instance methods: