欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS开发- runtime基本用法解析和用runtime给键盘添加工具栏和按钮响应事件

程序员文章站 2023-10-17 14:01:11
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,用得好的话能够省很多事,用不好的后果可能会被苹果拒绝,甚至说根本驾驭不了,博主这里只是浅层次的运用,每一门语言都博大精深,需要认真去研究。