使用的自定義類,如下: 動態變數控制 動態添加方法 動態交換兩個方法的實現 攔截並替換方法 在方法上增加額外功能 對runtime進行歸納總結,代碼如下: 1、載入運行時頭文件: 2、具體實現代碼: ...
- 使用的自定義類,如下:
#import <Foundation/Foundation.h> @interface Person : NSObject @property(nonatomic,copy) NSString *name; @property(nonatomic,copy) NSString *sex; -(NSString *)sayName; -(NSString *)saySex; @end
- 動態變數控制
- (void)viewDidLoad { [super viewDidLoad]; self.person = [Person new]; _person.name = @"xiaoming"; NSLog(@"XiaoMing first answer is %@",self.person.name); [self sayName]; } - (void)sayName { unsigned int count = 0; Ivar *ivar = class_copyIvarList([self.person class], &count); for (int i = 0; i<count; i++) { Ivar var = ivar[i]; const char *varName = ivar_getName(var); NSString *proname = [NSString stringWithUTF8String:varName]; if ([proname isEqualToString:@"_name"]) { //這裡別忘了給屬性加下劃線 object_setIvar(self.person, var, @"daming"); break; } } NSLog(@"XiaoMing change name is %@",self.person.name); }
- 動態添加方法
- (void)viewDidLoad { [super viewDidLoad]; self.person = [Person new]; [self sayFrom]; } - (void)sayFrom { class_addMethod([self.person class], @selector(guess), (IMP)guessAnswer, "v@:"); if ([self.person respondsToSelector:@selector(guess)]) { //Method method = class_getInstanceMethod([self.xiaoMing class], @selector(guess)); [self.person performSelector:@selector(guess)]; } else{ NSLog(@"Sorry,I don't know"); } } void guessAnswer(id self,SEL _cmd){ NSLog(@"function: guessAnswer"); NSLog(@"__%@__", NSStringFromSelector(_cmd)); } - (void) guess{ NSLog(@"function: guess"); NSLog(@"__%@__", NSStringFromSelector(_cmd)); }
- 動態交換兩個方法的實現
- (void)viewDidLoad { [super viewDidLoad]; self.person = [Person new]; NSLog(@"%@",_person.sayName); NSLog(@"%@",_person.saySex); Method m1 = class_getInstanceMethod([self.person class], @selector(sayName)); Method m2 = class_getInstanceMethod([self.person class], @selector(saySex)); method_exchangeImplementations(m1, m2); }
- 攔截並替換方法
@interface Tool : NSObject + (instancetype)sharedManager; - (NSString *)changeMethod; - (void)addCount; @end #import "Tool.h" @interface Tool () @property (nonatomic, assign) NSInteger count; @end @implementation Tool + (instancetype)sharedManager { static Tool *_sInstance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _sInstance = [[Tool alloc] init]; }); return _sInstance; } - (NSString *)changeMethod { return @"haha,你的方法被我替換掉了"; } - (void)addCount { _count += 1; NSLog(@"點擊次數------%ld", _count); } @end
- (void)viewDidLoad { [super viewDidLoad]; //這裡也可以使用 [self.person class],不過要先初始化 Method m1 = class_getInstanceMethod([Person class], @selector(sayName)); Method m2 = class_getInstanceMethod([Tool class], @selector(changeMethod)); method_exchangeImplementations(m1, m2); }
- 在方法上增加額外功能
@implementation FiveViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; button.frame = CGRectMake(100, 100, 100, 100); [button setTitle:@"按鈕" forState:UIControlStateNormal]; [button addTarget:self action:@selector(ButtonClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; } - (void)ButtonClick { NSLog(@"按鈕被點擊了"); } @end
- 對runtime進行歸納總結,代碼如下:
1、載入運行時頭文件:
#import <objc/runtime.h>
2、具體實現代碼:
/** 自定義類:MyObject */ //頭文件 #import <Foundation/Foundation.h> @interface MyObject : NSObject @property(strong,nonatomic) NSString *string; @property(strong,nonatomic) NSArray *array; - (void)method1; - (void)method2; - (void)classMethod1; @end //源文件 #import "MyObject.h" #import <objc/runtime.h> @interface MyObject (){ NSInteger _instance1; NSString *_instance2; } @property(assign,nonatomic) NSInteger intrger; - (void)method3WithArge1:(NSInteger)arge1 arge2:(NSString *)arge2; @end
@implementation MyObject -(void)classMethod1{ } - (void)method1{ NSLog(@"cell Method1"); } - (void)method2{ } - (void)method3WithArge1:(NSInteger)arge1 arge2:(NSString *)arge2{ NSLog(@"arge1 %ld arge2 %@",arge1,arge2); } + (BOOL)resolveInstanceMethod:(SEL)sel{ NSString *selector = NSStringFromSelector(sel); if ([selector isEqualToString:@"method1"]) { class_addMethod(self.class, @selector(method1), (IMP)functionForMethod1, "@:"); } return [super resolveInstanceMethod:sel]; } void functionForMethod1(id self,SEL _cmd){ NSLog(@"%@ %p",self,_cmd); } - (instancetype)forwardingTargetForSelector:(SEL)aSelector{ NSString *selector = NSStringFromSelector(aSelector); if([selector isEqualToString:@"method2"]){ //return; } return [super forwardingTargetForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation{ } @end /** 實現代碼 */ #import <objc/runtime.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //1.類相關函數 //得到類名 ViewController NSLog(@"%s",class_getName([self class])); //父類類名 //This is superClass 0x10f426da0 isa指針地址 NSLog(@"This is superClass %p",class_getSuperclass([self class])); //是否是元類 //Is MateClass 0 NSLog(@"Is MateClass %d",class_isMetaClass([self class])); //實例變數大小 //848 size_t a = class_getInstanceSize([self class]); NSLog(@"%ld",a); unsigned int outCount = 0; MyObject *objtect = [[MyObject alloc] init]; Class cls = objtect.class; //類名 NSLog(@"Class name %s",class_getName(cls)); //父類名字 NSLog(@"SuperClass name %s",class_getName(class_getSuperclass(cls))); //是否元類 NSLog(@"Is MetaClass %@",(class_isMetaClass(cls))?@"":@"NOT"); //變數大小 NSLog(@"MyObject size %ld",class_getInstanceSize(cls)); //變數信息 Ivar string = class_getInstanceVariable(cls, "_string"); if (string != NULL) { NSLog(@"MyObject instance messge %s",ivar_getName(string)); } // 屬性操作 objc_property_t *v = class_copyPropertyList(cls, &outCount); for (NSInteger i = 0; i< outCount; i++) { objc_property_t property = v[i]; NSLog(@"property is %s ",property_getName(property)); } free(v); //成員變數 Ivar *vars = class_copyIvarList(cls, &outCount); for (NSInteger i =0; i< outCount; i++) { Ivar ivar = vars[i]; NSLog(@"copyIvarList is %s is %ld",ivar_getName(ivar),i); } free(vars); //方法操作 Method *methods = class_copyMethodList(cls, &outCount); for (NSInteger i =0; i< outCount; i++) { Method met = methods[i]; #pragma clang diagnostic ignored"-Wformat" NSLog(@"Method is %s",method_getName(met)); } free(methods); // Format specifies type 'char *' but the argument has type 'SEL _Nonnull' // 獲取方法名 Method method = class_getInstanceMethod(cls,@selector(method1)); NSLog(@"Method name is %s",method_getName(method)); // 判斷方法是否存在 #pragma clang diagnostic ignored"-Wundeclared-selector" NSLog(@"Have you method %d",class_respondsToSelector(cls, @selector(method3WithArge1:arge2:))); // 指向函數實現的指針,相當於方法的實現 IMP imp = class_getMethodImplementation(cls, @selector(method1)); imp(); //動態創建類 #pragma clang diagnostic ignored" -Wunused-variable" // 註:運行時規定,只能在objc_allocateClassPair與objc_registerClassPair兩個函數之間為類添加變數 // 1.添加一個自定義的類 類名是MySubClass // 父類class,類名,額外空間 Class myClass = objc_allocateClassPair(objtect.class, "MySubClass", 0); // 2.增加方法,交換方法 //註: v@: 意思是 v是void @:沒有返回參數 if( class_addMethod(myClass, @selector(mysubMethod1),(IMP)mysubMethod1, "v@:")){ class_replaceMethod(myClass, @selector(method1), (IMP)mysubMethod1,"v@:"); } /* 3.增加一個NSSsting類型屬性 屬性名myString 變數size sizeof(NSString) 對齊 指針類型的為log2(sizeof(NSString*)) 類型 @encode(NSString*) class_addIvar(class,變數名,變數size,對齊,類型) */ //添加同名屬性會失敗 BOOL isd = class_addIvar(myClass, "_myString", sizeof(NSString *), log(sizeof(NSString *)), @encode(NSString *)); NSLog(@"屬性是否添加成功 %d",isd); /* 特性相關編碼 屬性的特性字元串 以 T@encode(type) 開頭, 以 V實例變數名稱 結尾,中間以特性編碼填充,通過property_getAttributes即可查看 特性編碼 具體含義 R readonly C copy & retain ARC strong N nonatomic G(name) getter=(name) S(name) setter=(name) D @dynamic W weak P 用於垃圾回收機制 */ //@T objc_property_attribute_t type; type.name = "T"; type.value = @encode(NSString *); //copy objc_property_attribute_t owership = {"C",""}; //nonatomic objc_property_attribute_t oeership2 = {"N",""}; //V_屬性名 objc_property_attribute_t var = {"V","_myString"}; //特性數組 objc_property_attribute_t attributes[] = {type,owership,oeership2,var}; //向類中添加名為myString的屬性,屬性的特性包含在attributes中 class_addProperty(myClass, "myString", attributes, 4); unsigned int propertyCount; objc_property_t * properties = class_copyPropertyList(myClass, &propertyCount); for (int i = 0; i<propertyCount; i++) { NSLog(@"屬性的名稱為 : %s",property_getName(properties[i])); NSLog(@"屬性的特性字元串為: %s",property_getAttributes(properties[i])); } //釋放屬性列表數組 free(properties); //在應用中註冊由objc_allocateClassPair創建的類 objc_registerClassPair(myClass); id instance = [[myClass alloc] init]; [instance performSelector:@selector(mysubMethod1)]; [instance performSelector:@selector(method1)]; // 銷毀一個類及相關聯的類 // 不過需要註意的是,如果程式運行中還存在類或其子類的實例,則不能調用針對類調用該方法 //objc_disposeClassPair(myClass); //關聯對象 UIView *view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; view.backgroundColor = [UIColor redColor]; [view setTapActionWithBlock:^{ NSLog(@"saAS"); }]; [self.view addSubview:view]; //SEL //Objective-C在編譯時,會依據每一個方法的名字、參數序列,生成一個唯一的整型標識(Int類型的地址),這個標識就是SEL //SEL只是一個指向方法的指針(準確的說,只是一個根據方法名hash化了的KEY值,能唯一代表一個方法 //而對於字元串的比較僅僅需要比較他們的地址就可以了,可以說速度上無語倫比 //sel : 0x104dd7735 /* 三種方法來獲取SEL: sel_registerName函數 Objective-C編譯器提供的@selector() NSSelectorFromString()方法 */ SEL sel1 = @selector(method1); NSLog(@"sel : %p", sel1); } static void mysubMethod1(id self,SEL _cmd){ NSLog(@"這是添加的方法"); } @end