1, 動態添加一個類, 就像KVO同樣, 系統是在程序運行的時候根據你要監聽的類, 動態添加一個新類繼承自該類, 而後重寫原類的setter方法並在裏面通知observer的.ide
// 建立一個類(size_t extraBytes該參數一般指定爲0, 該參數是分配給類和元類對象尾部的索引ivars的字節數。) Class clazz = objc_allocateClassPair([NSObject class], "GoodPerson", 0); // 添加ivar // @encode(aType) : 返回該類型的C字符串 class_addIvar(clazz, "_name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *)); class_addIvar(clazz, "_age", sizeof(NSUInteger), log2(sizeof(NSUInteger)), @encode(NSUInteger)); // 註冊該類 objc_registerClassPair(clazz); // 建立實例對象 id object = [[clazz alloc] init]; // 設置ivar [object setValue:@"Tracy" forKey:@"name"]; Ivar ageIvar = class_getInstanceVariable(clazz, "_age"); object_setIvar(object, ageIvar, @18); // 打印對象的類和內存地址 NSLog(@"%@", object); // 打印對象的屬性值 NSLog(@"name = %@, age = %@", [object valueForKey:@"name"], object_getIvar(object, ageIvar)); // 當類或者它的子類的實例還存在,則不能調用objc_disposeClassPair方法 object = nil; // 銷燬類 objc_disposeClassPair(clazz); ---------------------
2,函數
Person *p = [[Person alloc] init]; [p setValue:@"Kobe" forKey:@"name"]; [p setValue:@18 forKey:@"age"]; // p.address = @"廣州大學城"; p.weight = 110.0f; // 1.打印全部ivars unsigned int ivarCount = 0; // 用一個字典裝ivarName和value NSMutableDictionary *ivarDict = [NSMutableDictionary dictionary]; Ivar *ivarList = class_copyIvarList([p class], &ivarCount); for(int i = 0; i < ivarCount; i++){ NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivarList[i])]; id value = [p valueForKey:ivarName]; if (value) { ivarDict[ivarName] = value; } else { ivarDict[ivarName] = @"值爲nil"; } } // 打印ivar for (NSString *ivarName in ivarDict.allKeys) { NSLog(@"ivarName:%@, ivarValue:%@",ivarName, ivarDict[ivarName]); } // 2.打印全部properties unsigned int propertyCount = 0; // 用一個字典裝propertyName和value NSMutableDictionary *propertyDict = [NSMutableDictionary dictionary]; objc_property_t *propertyList = class_copyPropertyList([p class], &propertyCount); for(int j = 0; j < propertyCount; j++){ NSString *propertyName = [NSString stringWithUTF8String:property_getName(propertyList[j])]; id value = [p valueForKey:propertyName]; if (value) { propertyDict[propertyName] = value; } else { propertyDict[propertyName] = @"值爲nil"; } } // 打印property for (NSString *propertyName in propertyDict.allKeys) { NSLog(@"propertyName:%@, propertyValue:%@",propertyName, propertyDict[propertyName]); } // 3.打印全部methods unsigned int methodCount = 0; // 用一個字典裝methodName和arguments NSMutableDictionary *methodDict = [NSMutableDictionary dictionary]; Method *methodList = class_copyMethodList([p class], &methodCount); for(int k = 0; k < methodCount; k++){ SEL methodSel = method_getName(methodList[k]); NSString *methodName = [NSString stringWithUTF8String:sel_getName(methodSel)]; unsigned int argumentNums = method_getNumberOfArguments(methodList[k]); methodDict[methodName] = @(argumentNums - 2); // -2的緣由是每一個方法內部都有self 和 selector 兩個參數 } // 打印method for (NSString *methodName in methodDict.allKeys) { NSLog(@"methodName:%@, argumentsCount:%@", methodName, methodDict[methodName]); } ---------------------
3, post
-(void)changeAge{ unsigned int count = 0; //動態獲取XiaoMing類中的全部屬性[固然包括私有] Ivar *ivar = class_copyIvarList([self.xiaoMing class], &count); //遍歷屬性找到對應age字段 for (int i = 0; i<count; i++) { Ivar var = ivar[i]; const char *varName = ivar_getName(var); NSString *name = [NSString stringWithUTF8String:varName]; if ([name isEqualToString:@"_age"]) { //修改對應的字段值成20 object_setIvar(self.xiaoMing, var, @"20"); break; } } NSLog(@"XiaoMing's age is %@",self.xiaoMing.age); }
4, code
在有些時候咱們須要經過KVC去修改某個類的私有變量,可是又不知道該屬性是否存在,若是類中不存在該屬性,那麼經過KVC賦值就會crash,這時也能夠經過運行時進行判斷。一樣咱們在NSObject的分類中增長以下方法。server
#import "NSObject+objc.h" #import <objc/runtime.h> @implementation NSObject (objc) -(BOOL)hasProperty:(NSString *)property { BOOL flag = NO; u_int count = 0; Ivar *ivars = class_copyIvarList([self class], &count); for (int i = 0; i < count; i++) { const char *propertyName = ivar_getName(ivars[i]); NSString *propertyString = [NSString stringWithUTF8String:propertyName]; if ([propertyString isEqualToString:property]){ flag = YES; } } return flag; } @end
5, 對象
+(void)run { NSLog(@"Person Run....."); } +(void)study { NSLog(@"Person study....."); }
// 獲取兩個類的類方法 Method m1 = class_getClassMethod([Person class], @selector(run)); Method m2 = class_getClassMethod([Person class], @selector(study)); // 開始交換方法實現 method_exchangeImplementations(m1, m2);
[Person run]; [Person study];
6,繼承
// void(*)() // 默認方法都有兩個隱式參數, void eat(id self,SEL sel) { NSLog(@"%@ %@",self,NSStringFromSelector(sel)); } // 當一個對象調用未實現的方法,會調用這個方法處理,而且會把對應的方法列表傳過來. // 恰好能夠用來判斷,未實現的方法是否是咱們想要動態添加的方法 + (BOOL)resolveInstanceMethod:(SEL)sel { if (sel == @selector(eat)) { // 動態添加eat方法 // 第一個參數:給哪一個類添加方法 // 第二個參數:添加方法的方法編號 // 第三個參數:添加方法的函數實現(函數地址) // 第四個參數:函數的類型,(返回值+參數類型) v:void @:對象->self :表示SEL->_cmd class_addMethod(self, @selector(eat), eat, "v@:"); } return [super resolveInstanceMethod:sel]; }