Use the Runtime method in combination with the dynamic addition of instances.
Method substitution can replace any external class method. Dynamic addition can only be implemented in the object created by the added class, but can be used in combination with dynamic addition, it can be implemented by dynamically adding the required methods to any external class. This method can be a class method or an instance method. This external class can also be a class without any method declaration or implementation.
Main Idea: Use the runtime method to replace the custom method in the external classhy_resolveInstanceMethod
Orhy_resolveClassMethod
(Usehy_
Prefix indicates my custom method) andresolveInstanceMethod
OrresolveClassMethod
Method replacement.hy_resolveInstanceMethod
Orhy_resolveClassMethod
The method should be written inresolveInstanceMethod
OrresolveClassMethod
The logic of the dynamic addition method of runtime written in the method.
It's a bit difficult, but at least you need to read the source code and think about the logic. The premise is that you are familiar with the runtime method.
Defects: 1. It is difficult to process methods with parameters. The parameter values must be determined based on the actual business logic.
Before use
import <objc/message.h>
, Need following:
Create Person. h and Person. m
Person. h:
1 #import <Foundation/Foundation.h>2 3 @interface Person : NSObject4 5 @end
Person. m:
1 #import "Person.h"2 3 @implementation Person4 5 @end
Create OtherPerson. h and OtherPerson. m
OtherPerson. h:
1 #import <Foundation/Foundation.h>2 3 @interface OtherPerson : NSObject4 5 6 @end
OtherPerson. m:
1 // 2 // Created by HEYANG on 16/1/11. 3 // Copyright©2016 HEYANG. all rights reserved. 4 // 5 6 # import "OtherPerson. h "7 # import <objc/message. h> 8 9 @ implementation OtherPerson10 11 12 + (void) load {13 Class clazz = NSClassFromString (@ "Person "); 14 15 // obtain the class Method before replacement 16 Method instance_eat = 17 class_getClassMethod (clazz, @ selector (resolveInstanceMethod :)); 18 // get the replaced class Method 19 Method instance_notEat = 20 class_getClassMethod (self, @ selector (handler :)); 21 22 // then switch Class Method 23 method_exchangeImplementations (instance_eat, instance_notEat); 24 25 // obtain the Class Method 26 before replacement Method class_eat = 27 class_getClassMethod (clazz, @ selector (resolveClassMethod :)); 28 // obtain the replaced class Method 29 Method class_notEat = 30 class_getClassMethod (self, @ selector (handler :)); 31 32 // then switch Class Method 33 method_exchangeImplementations (class_eat, class_notEat); 34 35} 36 37 void eat_1 (id self, SEL sel) 38 {39 NSLog (@ "Stop eating "); 40 NSLog (@ "% @", self, NSStringFromSelector (sel); 41} 42 void eat_2 (id self, SEL sel, NSString * str1, NSString * str2) 43 {44 NSLog (@ "don't eat"); 45 NSLog (@ "% @", self, NSStringFromSelector (sel )); 46 NSLog (@ "Print two parameter values: % @ and % @", str1, str2); 47} 48 49 50 + (BOOL) hy_resolveInstanceMethod :( SEL) sel {51 // when sel is in the implementation method, the eat method 52 if (sel = NSSelectorFromString (@ "eat ")) {53 // Add the eat method 54 dynamically 55 // The first parameter: Add Method 56 to the class // The second parameter: add Method number 57 // third parameter: add method function implementation (function address) 58 // fourth parameter: function type, (Return Value + parameter type) v: void @: Object-> self: SEL-> _ prop 59 class_addMethod (self, sel, (IMP) eat_1, "v @:"); 60} 61 return YES; 62} 63 + (BOOL) hy2_resolveClassMethod :( SEL) sel {64 65 if (sel = NSSelectorFromString (@ "eat: :")) {66 67 class_addMethod (objc_getMetaClass ("Person"), sel, (IMP) eat_2, "v #:@"); 68} 69 70 return YES; 71} 72 73 @ end
Last In file 'main. M ':
Main. m:
1/** 2*3 * Swap Method and Dynamic add Method (exchange Method and Dynamic addition Method) 4*5 */6 7 # import <Foundation/Foundation. h> 8 9 // ignore undeclared warm ignores undeclared warning 10 # pragma clang diagnostic push11 # pragma clang diagnostic ignored "-Wundeclared-selector" 12 13 int main (int argc, const char * argv []) {14 @ autoreleasepool {15 // get this Person class get this Person Class 16 class clazz = NSClassFromString (@ "Person "); 17 // get this Person Instance 18 id person = [[clazz alloc] init]; 19 20 // send message to 'eid' method in Person Class or Person Instance21 // The 'not' method used to send a message to the Person Class or Person instance does not include parameter 22 [person already mselector: @ selector (eat) withObject: nil]; 23 // The 'eid' Method for sending a message to the Person class contains two parameters 24 [clazz notify mselector: @ selector (eat: with :) 25 withObject: @ "Hello" 26 withObject: @ "World"]; 27} 28 return 0; 29} 30 31 # pragma clang diagnostic pop
The code test result
Extra
Download
Download github code source