1.如何用runtime給鍵盤添加工具欄和按鈕響應事件:
.h #import#import @interface KeyBoardTool : NSObject /** * 增加隱藏鍵盤按鈕 * * @param textfield 輸入框對象 */ + (void)hideKeyboard:(UITextField *)textfield; @end .m #pragma mark - 增加隱藏鍵盤按鈕 + (void)hideKeyboard:(UITextField *)textfield { //為鍵盤增加工具欄 UIToolbar * topView = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, 40)]; [topView setBarStyle:UIBarStyleDefault]; [textfield setInputAccessoryView:topView]; UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame = CGRectMake(0, 5, 40, 30); [btn addTarget:self action:@selector(dismissKeyBoard:) forControlEvents:UIControlEventTouchUpInside]; [btn setBackgroundImage:[UIImage imageNamed:@"closed"] forState:UIControlStateNormal]; //將TextField綁定到button上,kTextField要和UITextField創建的對象名一致 /* 第一個參數是需要添加屬性的對象; 第二個參數是屬性的key; 第三個參數是屬性的值; 第四個參數是一個枚舉值,類似@property屬性創建時設置的關鍵字,可從命名看出各含義 */ objc_setAssociatedObject(btn, kTextField, textfield, OBJC_ASSOCIATION_RETAIN_NONATOMIC); //UIBarButtonSystemItemFlexibleSpace自動調節按鈕間距 UIBarButtonItem * leftBtn = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:self action:nil]; //如果希望左側顯示按鈕,重新實例化一個按鈕用 CustomView 方法設置,類似下面的rightBtn。 UIBarButtonItem *rightBtn = [[UIBarButtonItem alloc] initWithCustomView:btn]; NSArray * buttonsArray = [NSArray arrayWithObjects:leftBtn,rightBtn,nil]; [topView setItems:buttonsArray]; } + (void)dismissKeyBoard:(UIButton *)button{ //獲取button上對應的屬性,kTextField要和UITextField創建的對象名一致 [objc_getAssociatedObject(button, kTextField) resignFirstResponder]; }
其實這些都是固定的方法,一開始接觸綁定的方法看不懂,也沒什麼好理解的,記住就好。
2.獲取某一個類所有屬性和所有方法
+ (void)getAllPropertyAndAllMethod:(id)myClass { unsigned int outCount = 0; // 獲取到所有的成員變量列表 Ivar *vars = class_copyIvarList([myClass class], &outCount); // 遍歷所有的成員變量 for (int i = 0; i < outCount; i++) { Ivar ivar = vars[i]; // 取出第i個位置的成員變量 const char *propertyName = ivar_getName(ivar); // 獲取變量名 const char *propertyType = ivar_getTypeEncoding(ivar); // 獲取變量編碼類型 printf("%s/%s\n", propertyName, propertyType); } unsigned int count; //獲取方法列表,所有在.m文件顯式實現的方法都會被找到,包括setter+getter方法; Method *allMethods = class_copyMethodList([myClass class], &count); for(int i =0;i<count;i++) char="" const="" md="allMethods[i];" method="" methodname="sel_getName(sel);" pre="" sel="">
通過以上方法可以看到許多隱藏的屬性和方法,但是,請慎用,比較常用的方法有設置placeholder的字體大小:
[_loginTestField setValue:[UIFont systemFontOfSize:14] forKeyPath:@"_placeholderLabel.font"];
3.改變屬性值
+ (void)changeVariable { ViewController *viewVC = [[ViewController alloc]init]; NSLog(@"改變前的viewVC:%@",viewVC); unsigned int count = 0; Ivar *vars = class_copyIvarList([ViewController class], &count); Ivar ivv = vars[0]; //從第一個方法getAllVariable中輸出的控制台信息,我們可以看到實例屬性。 object_setIvar(viewVC, ivv, @"world"); //屬性被強制改為world。 NSLog(@"改變之後的viewVC:%@",viewVC); }
從上面方法中能看出來改變的是ViewController中第一個實例屬性的值。
4.增加新方法
+ (void)addNewMethod { /* 動態添加方法: 第一個參數表示Class cls 類型; 第二個參數表示待調用的方法名稱; 第三個參數(IMP)myAddingFunction,IMP一個函數指針,這裡表示指定具體實現方法myAddingFunction; 第四個參數表方法的參數,0代表沒有參數; */ ViewController *viewVC = [[ViewController alloc]init]; class_addMethod([viewVC class], @selector(myNewMethod), (IMP)addingMethod, 0); //調用方法 [viewVC performSelector:@selector(myNewMethod)]; } //這個方法不調用,但是不寫的話會報警告 - (void)myNewMethod { } //具體的實現(方法的內部都默認包含兩個參數Class類和SEL方法,被稱為隱式參數。) int addingMethod(id self, SEL _cmd){ NSLog(@"已新增方法:myNewMethod"); return 1; }
5.交換方法
+ (void)exchangeMethod { ViewController *viewVC = [[ViewController alloc]init]; Method method1 = class_getInstanceMethod([viewVC class], @selector(method1)); Method method2 = class_getInstanceMethod([viewVC class], @selector(method2)); //交換方法 method_exchangeImplementations(method1, method2); [viewVC method1]; }
在ViewController中有method1和method2兩個方法,method_exchangeImplementations交換了這兩個方法,所以當調用method1,實際上調用的是method2.
6.增加新屬性 假如要給ViewController添加新屬性,先創建一個繼承於ViewController的category,然後下面看代碼:
.h #import "ViewController.h" @interface ViewController (VVC) @property (nonatomic,strong)NSString *vccVariable; @end .m #import "ViewController+VVC.h" #import//runtime API的使用需要包含此頭文件 const char * vcc = "vcckey"; //做為key,字符常量 必須是C語言字符串; @implementation ViewController (VVC) -(void)setVccVariable:(NSString *)vccVariable{ NSString *newStr = [NSString stringWithFormat:@"%@",vccVariable]; /* 第一個參數是需要添加屬性的對象; 第二個參數是屬性的key; 第三個參數是屬性的值; 第四個參數是一個枚舉值,類似@property屬性創建時設置的關鍵字,可從命名看出各含義 */ objc_setAssociatedObject([ViewController class],vcc, newStr, OBJC_ASSOCIATION_COPY_NONATOMIC); } //提取屬性的值: -(NSString *)vccVariable{ NSString *myVccVariable = objc_getAssociatedObject([ViewController class], vcc); return myVccVariable; } @end
Demo下載地址:https://github.com/codeliu6572/Runtime_use 學習runtime,也許看起來不是很好懂,就好比我們剛學習一門新的語言,我們從沒見過這樣的代碼,最簡單的方法就是記住,但是對於runtime,用得好的話能夠省很多事,用不好的後果可能會被蘋果拒絕,甚至說根本駕馭不了,博主這裡只是淺層次的運用,每一門語言都博大精深,需要認真去研究。