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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 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,用得好的话能够省很多事,用不好的后果可能会被苹果拒绝,甚至说根本驾驭不了,博主这里只是浅层次的运用,每一门语言都博大精深,需要认真去研究。

目录
相关文章
|
25天前
|
iOS开发 开发者 MacOS
深入探索iOS开发中的SwiftUI框架
【10月更文挑战第21天】 本文将带领读者深入了解Apple最新推出的SwiftUI框架,这一革命性的用户界面构建工具为iOS开发者提供了一种声明式、高效且直观的方式来创建复杂的用户界面。通过分析SwiftUI的核心概念、主要特性以及在实际项目中的应用示例,我们将展示如何利用SwiftUI简化UI代码,提高开发效率,并保持应用程序的高性能和响应性。无论你是iOS开发的新手还是有经验的开发者,本文都将为你提供宝贵的见解和实用的指导。
118 66
|
11天前
|
存储 监控 API
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
|
7天前
|
JSON 供应链 搜索推荐
淘宝APP分类API接口:开发、运用与收益全解析
淘宝APP作为国内领先的购物平台,拥有丰富的商品资源和庞大的用户群体。分类API接口是实现商品分类管理、查询及个性化推荐的关键工具。通过开发和使用该接口,商家可以构建分类树、进行商品查询与搜索、提供个性化推荐,从而提高销售额、增加商品曝光、提升用户体验并降低运营成本。此外,它还能帮助拓展业务范围,满足用户的多样化需求,推动电商业务的发展和创新。
26 5
|
1月前
|
安全 前端开发 Android开发
探索移动应用与系统:从开发到操作系统的深度解析
在数字化时代的浪潮中,移动应用和操作系统成为了我们日常生活的重要组成部分。本文将深入探讨移动应用的开发流程、关键技术和最佳实践,同时分析移动操作系统的核心功能、架构和安全性。通过实际案例和代码示例,我们将揭示如何构建高效、安全且用户友好的移动应用,并理解不同操作系统之间的差异及其对应用开发的影响。无论你是开发者还是对移动技术感兴趣的读者,这篇文章都将为你提供宝贵的见解和知识。
|
1月前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
108 3
|
iOS开发
设计iOS中随系统键盘弹收和内容文字长度自适应高度的文本框
设计iOS中随系统键盘弹收和内容文字长度自适应高度的文本框
220 0
设计iOS中随系统键盘弹收和内容文字长度自适应高度的文本框
|
2月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
1月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
2月前
|
存储 前端开发 Swift
探索iOS开发:从新手到专家的旅程
本文将带您领略iOS开发的奇妙之旅,从基础概念的理解到高级技巧的掌握,逐步深入iOS的世界。文章不仅分享技术知识,还鼓励读者在编程之路上保持好奇心和创新精神,实现个人成长与技术突破。

推荐镜像

更多