Objective-C Runtime
Describes the MACOs objective-C Runtime Library support functions and data structures. overview (overview) the definition of runtime in the official document the objective-C Runtime is a Runtime Library that provides support for the dynamic properties of the objective-C language, and as such is linked to by all objective-C apps. the official Runtime Library gives objective-C language dynamic attributes, all OC apps can directly use it you typically don't need to use the objective-C Runtime library directly when programming in objective-C. this API is useful primarily for developing bridge layers between objective-C and other extensions ages, or for low-level debugging. generally, the Runtime Library is not directly used in programming. The runtime function or attribute is generally used in cross-origin programming, or in the lower-layer debug.
Note
All
char *
In the Runtime API shocould be considered to have UTF-8 encoding. in the Runtime API, all char types are encoded in UTF-8. The above is a brief introduction to runtime in this document. After reading other people's experience in runtime and their own practices, currently, the concept of Runtime is: Message dynamic parsing, message redirection, message forwarding, dynamic parsing at runtime (program running), dynamic: a defined but unimplemented method in the class, dynamically bind implementation methods to the class or bind methods that are neither defined nor implemented. To put it simply, add methods to the class. The next step is the introduction of the runtime method, we will pause here to give a simple description of the above concepts. Before that, let's take a look at the implementation process of [handler message, that is, how the message mechanism works.
1 struct objc_class { 2 Class isa OBJC_ISA_AVAILABILITY; 3 #if !__OBJC2__ 4 Class super_class OBJC2_UNAVAILABLE; 5 const char *name OBJC2_UNAVAILABLE; 6 long version OBJC2_UNAVAILABLE; 7 long info OBJC2_UNAVAILABLE; 8 long instance_size OBJC2_UNAVAILABLE; 9 struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;10 struct objc_method_list **methodLists OBJC2_UNAVAILABLE;11 struct objc_cache *cache OBJC2_UNAVAILABLE;12 struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;13 #endif14 } OBJC2_UNAVAILABLE;
Each nsobject object has a member variable list, method list, cache, and interface list. The method pointer (IMP) is stored in the method list) the cache stores the called method [Receiver message]; it is converted to the message sending mode:
id objc_msgSend(id self, SEL _cmd, …);
When an object receives a message, it checks the message in the following order, if a response is received at any stage, the system ends. Otherwise, an error is returned. The system receives the message from the object and checks whether a matching method exists in the cache, if there is a response, otherwise, continue-> check whether there are matching methods in the method list, if there is a response, otherwise continue-> check whether there are matching methods in the parent class, if yes, the response will continue.-> enter dynamic resolution + (bool) resolveinstancemethod :( SEL) SEL. If a dynamic resolution method is specified, the response will continue.-> enter message redirection-(ID) forwardingtargetforselector :( SEL) aselector. If a specified message receiving object exists, the message will be forwarded to the receiving object for response; otherwise, the message will continue-> Start message forwarding-(void) forwardinvocation :( nsinvocation *) aninvocation, if a forwarding object is specified, it is forwarded to the object for response, otherwise, we will have two chances to modify or set the implementation of the Object method before throwing an exception and forwarding the message. Next we will talk about dynamic parsing one by one. If we have a classa, in its header file, we define a-(void) printname; method, but we do not. in the M file, let it be implemented. If we use [[classa new] printname] directly in viewcontroller, the program will not go wrong, but will not do anything. We can rewrite resolveinstancemethod: Or resolveclassmethod: method, here we add implementation for the printname Method
1/** 2 method to be dynamically bound 3 4 @ Param self object to bind method 5 @ Param _ cmd method information 6 */7 void dynamicmethodimp (ID self, sel _ cmd) {8 9 nslog (@ "sel: % s method is added", sel_getname (_ cmd); 10 nslog (@ "Name: jackey "); 11} 12 13 14/** 15 dynamic binding and Resolution Methods 16 17 @ Param sel method information 18 @ return whether the method has been processed 19 */20 + (bool) resolveinstancemethod :( SEL) SEL {21 22 nslog (@ "sel: % s method does not exist", sel_getname (SEL )); 23 24 if (SEL = @ selector (printname) {25 26 class_addmethod ([self class], Sel, (IMP) dynamicmethodimp, "[email protected]:"); 27 return yes; 28} 29 30 return [Super resolveinstancemethod: sel]; 31}
Then, run [[classa new] printname]; and The name: jackey will be output.
Redirection:
If the message is not responded after dynamic resolution, it will enter the redirection stage.
We can override-(ID) forwardingtargetforselector :( SEL) aselector to redirect messages to objects that can respond
1/** 2 method redirection 3 4 @ Param aselector method information 5 @ return returns the redirected object 6 */7-(ID) forwardingtargetforselector :( SEL) aselector {8 9 nslog (@ "current class can't response to sel: % s", sel_getname (aselector); 10 11 if (aselector ==@ selector (printrightname )) {12 13 nslog (@ "forward to target: % @", [classb class]); 14 return [classb new]; 15} 16 17 return [Super forwardingtargetforselector: aselector]; 18 19}
If no processing is performed before, the message will be forwarded. We can rewrite
-(Nsmethodsignature *) methodsignatureforselector :( SEL) selector;
-(Void) forwardinvocation :( nsinvocation *) aninvocation;
Customize
1/** 2 get method signature 3 4 @ Param selector method information 5 @ return nsinvocation message object 6 */7-(nsmethodsignature *) methodsignatureforselector :( SEL) selector {8 9 nsstring * sel = nsstringfromselector (selector); 10 if ([sel rangeofstring: @ "set"]. location = 0) {11 12 return [nsmethodsignature signaturewithobjctypes: "[email protected]: @"]; 13} 14 else {15 16 return [nsmethodsignature signaturewithobjctypes :"@@: "]; 17} 18} 19 20/** 21 forward 22 23 @ Param aninvocation message object 24 */25-(void) forwardinvocation :( nsinvocation *) aninvocation {26 27 nslog (@ "no class can't response to sel: % s", sel_getname ([aninvocation selector]); 28 29 classc * c = [classc new]; 30 if ([C respondstoselector: [aninvocation selector]) {31 32 nslog (@ "method apply deliver to % @", [classc class]); 33 [aninvocation invokewithtarget: C]; 34} 35 36 else {37 38 [Super forwardinvocation: aninvocation]; 39} 40}
Message forwarding makes up for the problem that OC cannot inherit more
Finally, let's take a look at method swizzling.
We can directly modify the method pointer so that a method name points to another method implementation.
1 Method ori_method = class_getInstanceMethod([ClassB class], @selector(printRightName));2 Method my_method = class_getInstanceMethod([ClassC class], @selector(printFamilyName));3 4 method_exchangeImplementations(ori_method, my_method);5 6 [[ClassB new] printRightName];
Using method_exchangeimplementation to exchange pointers of two object Methods
Printrightname: printfamilyname
Objective-C Runtime first recognized