ios runtime部分事例方法說明
一.場景--動態改變變量
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); self.textfield.text = self.self.person.name;
方法說明:
1.Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
用法:返回類的所有屬性和變量
參數:class 類型
outCount 類型的數目
返回:Ivar 指針 當做組來用
拓展:class_copyPropertyList 返回對象類的屬性(@property申明的屬性)
2.const char *ivar_getName(Ivar v)
用法: 返回實例變量的名稱。
拓展:ivar_getOffset: 返回實例變量的偏移量。
ivar_getTypeEncoding:返回實例變量的類型字符串。
3. void object_setIvar(id obj, Ivar ivar, id value)
用法:修改類型的變量
參數:obj 所選類
ivar 實例變量
value 更改變量
拓展:id object_getIvar(id obj, Ivar ivar) 獲取類實例的變量
二、場景--添加方法
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"); } self.textview.text = @"beijing";
1.BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) //Adds a new method to a class with a given name and implementation.
用法:為類添加一個方法
參數:class 類
SEL 方法選擇器 相當於名字
IMP 方法指針
types 描述方法參數類型的字符數組
說明:sel與方法指針名字可以不同 一個是名字 一個是指針地址
三、場景--動態方法交換
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);
1.Method class_getInstanceMethod(Class cls, SEL name) 用法:獲取某類的方法(Method類)
參數:class 類
SEL 方法選擇器
2.void method_exchangeImplementations(Method m1, Method m2) 用法:交換方法
參數:Method 方法
四、場景--替換方法
//這裡也可以使用 [self.person class],不過要先初始化 Method m1 = class_getInstanceMethod([Person class], @selector(sayName)); Method m2 = class_getInstanceMethod([Tool class], @selector(changeMethod)); method_exchangeImplementations(m1, m2);
用法說過了,嗯!
五:場景--方法上增加額外功能
+ (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class selfClass = [self class]; SEL oriSEL = @selector(sendAction:to:forEvent:); Method oriMethod = class_getInstanceMethod(selfClass, oriSEL); SEL cusSEL = @selector(mySendAction:to:forEvent:); Method cusMethod = class_getInstanceMethod(selfClass, cusSEL); BOOL addSucc = class_addMethod(selfClass, oriSEL, method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod)); if (addSucc) { class_replaceMethod(selfClass, cusSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod)); }else { method_exchangeImplementations(oriMethod, cusMethod); } }); }
- (void)mySendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
[[Tool sharedManager] addCount];
[self mySendAction:action to:target forEvent:event];
}
說明:在程序運行時,Runtime會將所有的Class和Category加載到內存中,這時,會調用類的load方法,通知我們Class或Category已經被加載到內存中。
代碼邏輯:交換了方法 ,執行邏輯就改變了 :mySendAction觸發->再次調用轉到原有sendAction方法
1. IMP method_getImplementation(Method m)
用法:獲取IMP
拓展:const char *method_getTypeEncoding(Method m) 獲取說明
SEL method_getName(Method m) 獲取name(SEL)
2.IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
用法:Replaces the implementation of a method for a given class.
注意:註銷 free(ivars);
參考資料來源:https://github.com/Tuccuay/RuntimeSummary