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

释放双眼,带上耳机,听听看~!

1.如何用runtime给键盘添加工具栏和按钮响应事件:

.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@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++)
{
//Method,为runtime声明的一个宏,表示对一个方法的描述
Method md = allMethods[i];
//获取SEL:SEL类型,即获取方法选择器@selector()
SEL sel = method_getName(md);
//得到sel的方法名:以字符串格式获取sel的name,也即@selector()中的方法名称
const char *methodname = sel_getName(sel);
NSLog(@"(Method:%s)",methodname);
}
}

通过以上方法可以看到许多隐藏的属性和方法,但是,请慎用,比较常用的方法有设置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)addingMethod,IMP一个函数指针,这里表示指定具体实现方法addingMethod;
第四个参数表方法的参数,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 <objc/runtime.h> //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,用得好的话能够省很多事,用不好的后果可能会被苹果拒绝,甚至说根本驾驭不了,博主这里只是浅层次的运用,每一门语言都博大精深,需要认真去研究。

为TA充电
共{{data.count}}人
人已赞赏
iOS文章

iOS开发UISearchController的使用和改善方法

2021-2-3 2:52:37

iOS文章

iOS开发点赞动画效果

2021-2-3 4:07:37

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索