iOS开发- runtime基本用法解析和用runtime给键盘添加工具栏和按钮响应事件
程序员文章站
2022-06-02 23:52:23
1.如何用runtime给键盘添加工具栏和按钮响应事件:
.h
#import
#import
@interface keyboardtool : nsobject
/**...
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,用得好的话能够省很多事,用不好的后果可能会被苹果拒绝,甚至说根本驾驭不了,博主这里只是浅层次的运用,每一门语言都博大精深,需要认真去研究。