Runtime 方法替換 和 動態添加實例方法 結合使用


前言:

方法替換,可以替換任意外部類的方法,而動態添加方法只能實現在被添加類創建的對象里,但是將方法替換和動態添加方法結合使用,可以實現,對任意外部類動態添加需要的方法,這個方法可以是類方法也可以是實例方法,這個外部類也可以是沒有任何方法聲明和實現的類。

主要思路:

使用運行時的方法替換將在外部類將自定義方法hy_resolveInstanceMethodhy_resolveClassMethod(用hy_前綴表示是我自定義的方法)和需要被添加的類中的resolveInstanceMethod或者resolveClassMethod方法替換,替換之前在hy_resolveInstanceMethodhy_resolveClassMethod方法內部寫好本應該在resolveInstanceMethod或者resolveClassMethod方法內部寫好的runtime動態添加方法的邏輯。

可能有點繞,不過至少需要繼續閱讀源碼,思考其中的邏輯,其實不難,前提是熟悉使用runtime的方法。

 

缺陷:1、含參數的方法難以處理,參數值需要根據實際業務邏輯而定。

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 : NSObject
4 
5 @end
Person.m:
1 #import "Person.h"
2 
3 @implementation Person
4 
5 @end

Create OtherPerson.h and OtherPerson.m

OtherPerson.h:

1 #import <Foundation/Foundation.h>
2 
3 @interface OtherPerson : NSObject
4 
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 OtherPerson
10 
11 
12 +(void)load{
13     Class clazz = NSClassFromString(@"Person");
14     
15     //獲取替換前的類方法
16     Method instance_eat = 
17         class_getClassMethod(clazz, @selector(resolveInstanceMethod:));
18     //獲取替換后的類方法
19     Method instance_notEat = 
20         class_getClassMethod(self, @selector(hy_resolveInstanceMethod:));
21     
22     //然后交換類方法
23     method_exchangeImplementations(instance_eat, instance_notEat);
24     
25     //獲取替換前的類方法
26     Method class_eat = 
27         class_getClassMethod(clazz, @selector(resolveClassMethod:));
28     //獲取替換后的類方法
29     Method class_notEat = 
30         class_getClassMethod(self, @selector(hy2_resolveClassMethod:));
31     
32     //然后交換類方法
33     method_exchangeImplementations(class_eat, class_notEat);
34     
35 }
36 
37 void eat_1(id self,SEL sel)
38 {
39     NSLog(@"到底吃不吃飯了");
40     NSLog(@"%@ %@",self,NSStringFromSelector(sel));
41 }
42 void eat_2(id self,SEL sel, NSString* str1,NSString* str2)
43 {
44     NSLog(@"到底吃不吃飯了");
45     NSLog(@"%@ %@",self,NSStringFromSelector(sel));
46     NSLog(@"打印兩個參數值:%@ and %@",str1,str2);
47 }
48 
49 
50 +(BOOL)hy_resolveInstanceMethod:(SEL)sel{
51     //當sel為實現方法中 有 eat 方法
52     if (sel == NSSelectorFromString(@"eat")) {
53         //就 動態添加eat方法
54         
55         // 第一個參數:給哪個類添加方法
56         // 第二個參數:添加方法的方法編號
57         // 第三個參數:添加方法的函數實現(函數地址)
58         // 第四個參數:函數的類型,(返回值+參數類型) v:void @:對象->self :表示SEL->_cmd
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:with:")) {
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 (交換方法和動態添加方法)
 4  *
 5  */
 6  
 7 #import <Foundation/Foundation.h>
 8 
 9 //ignore undeclared warm 忽視未聲明的警告
10 #pragma clang diagnostic push
11 #pragma clang diagnostic ignored "-Wundeclared-selector"
12 
13 int main(int argc, const char * argv[]) {
14     @autoreleasepool {
15         //get this Person class 拿到了這個Person類
16         Class clazz = NSClassFromString(@"Person");
17         //get this Person Instance 拿到這個Person實例
18         id person = [[clazz alloc] init];
19         
20         //send message to 'eat' method in Person Class or Person Instance
21         //發送消息給Person類或者Person實例的‘eat’方法 不含參數
22         [person performSelector:@selector(eat) withObject:nil];
23         //發送消息給Person類的‘eat’方法 含兩個參數
24         [clazz performSelector:@selector(eat:with:) 
25                         withObject:@"Hello" 
26                         withObject:@"World"];
27     }
28     return 0;
29 }
30 
31 #pragma clang diagnostic pop

the code test result

the code test result picture

extra

download

download github code source


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM