Runtime的使用

简介: Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的。

Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的。比如:


id objc = [NSObject alloc]
objc = [objc init]


类方法本质:类对象调用[NSObject class]


id:谁发送消息

SEL: 发送什么消息


苹果运行使用objc_msgSend,如没有提示则到build setting搜索msg改为no


底层运行时会转化成发送消息


id objc = objc_msgSend(objc_getClass("NSObject"),sel_registerName("alloc"));
objc = objc_msgSend(objc,sel_registerName("init"));


最终生成消息机制,编译器做的事


最终代码,需要把当前代码重新编译,用code编译器,clang


clang -rewrite-objc 文件名


开发中runtime的使用场景:1.不得不用runtime消息机制,可以帮我们调用私有方法。2.runtime一般都是针对系统的类

方法调用流程


怎么去调用方法,对象方法:类对象的方法列表,类方法:元类中方法列表


1.通过isa指针去对应的类中查找

2.注册方法编号

3.根据方法编号去查找对应的方法

4.找到的只是最终函数实现地址,根据地址去方法去调用方法


内容五大区:栈、堆、静态区、常量区、方法区


1.栈:不需要手动管理内存,自动管理

2.堆:需要手动管理内存,自己去释放


method函数的解析


SEL selector 的简写,俗称方法选择器,实质存储的是方法的名称


IMP implement 的简写,俗称方法实现,看源码得知它就是一个函数指针


Method 对上述两者的一个包装结构.


//判断类中是否包含某个方法的实现
  BOOL class_respondsToSelector(Class cls, SEL sel)
  //获取类中的方法列表
  Method *class_copyMethodList(Class cls, unsigned int *outCount) 
  //为类添加新的方法,如果方法该方法已存在则返回NO
  BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
  //替换类中已有方法的实现,如果该方法不存在添加该方法
  IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) 
  //获取类中的某个实例方法(减号方法)
  Method class_getInstanceMethod(Class cls, SEL name)
  //获取类中的某个类方法(加号方法)
  Method class_getClassMethod(Class cls, SEL name)
  //获取类中的方法实现
  IMP class_getMethodImplementation(Class cls, SEL name)
  //获取类中的方法的实现,该方法的返回值类型为struct
  IMP class_getMethodImplementation_stret(Class cls, SEL name) 
  //获取Method中的SEL
  SEL method_getName(Method m) 
  //获取Method中的IMP
  IMP method_getImplementation(Method m)
  //获取方法的Type字符串(包含参数类型和返回值类型)
  const char *method_getTypeEncoding(Method m) 
  //获取参数个数
  unsigned int method_getNumberOfArguments(Method m)
  //获取返回值类型字符串
  char *method_copyReturnType(Method m)
  //获取方法中第n个参数的Type
  char *method_copyArgumentType(Method m, unsigned int index)
  //获取Method的描述
  struct objc_method_description *method_getDescription(Method m)
  //设置Method的IMP
  IMP method_setImplementation(Method m, IMP imp) 
  //替换Method
  void method_exchangeImplementations(Method m1, Method m2)
  //获取SEL的名称
  const char *sel_getName(SEL sel)
  //注册一个SEL
  SEL sel_registerName(const char *str)
  //判断两个SEL对象是否相同
  BOOL sel_isEqual(SEL lhs, SEL rhs) 
  //通过块创建函数指针,block的形式为^ReturnType(id self,参数,...)
  IMP imp_implementationWithBlock(id block)
  //获取IMP中的block
  id imp_getBlock(IMP anImp)
  //移出IMP中的block
  BOOL imp_removeBlock(IMP anImp)
  //调用target对象的sel方法
  id objc_msgSend(id target, SEL sel, 参数列表...)


动态添加方法class_addMethod


//resolveInstanceMethod对应的对象方法,resolveClassMethod对应的是类方法
//什么时候调用:只要一个对象调用了一个来实现的方法就就调用这个方法,进行处理
//作用:动态添加方法,处理为实现的方法
//class :给那个类添加方法
//SEL:添加那个方法
//IMP:implementation方法实现->函数->函数入口->函数名
//type:方法类型
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == NSSelecterFromString(@"run:"))
    class_addMethod(self, sel, (IMP)aaa,"v@:@");
    return YES;
}
//任何方法默认都有两个隐式参数,self,_cmd
void aaa(id self,SEL _cmd,NSNumber *num) {
    NSLog(@"跑了%@米",num);
}


TypeEncoding表


微信图片_20221018091536.png

TypeEncoding


动态添加属性


@interface NSObject (JHObject)
//@property分类:只会生成set,get方法声明,不会生成实现,也不会生成下划线成员属性
@property NSString *name;
@end
@implementation NSObject (JHObject)
-(void)setName:(NSString *)name{
    //object:给那个对象添加属性
//    key 属性名称
//    value 属性值
//    policy 保存策略
//    objc_setAssociatedObject(<#id  _Nonnull object#>, <#const void * _Nonnull key#>, <#id  _Nullable value#>, <#objc_AssociationPolicy policy#>)
    objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_COPY);
}
-(NSString *)name{
    return objc_getAssociatedObject(self, "name");
}
@end


交换方法


使用场景:当我们需要在系统方法里做事情时


示例:修改系统默认字体


//把类加载进内存的时候调用,只会调用一次
+(void)load {
//    系统方法
    Method fun1 = class_getClassMethod(self, @selector(systemFontOfSize:));
//    自定义UIFont字体类型的方法
    Method fun2 = class_getClassMethod(self, @selector(jh_systemFontOfSize:));
//    交换方法1和方法2
    method_exchangeImplementations(fun1, fun2);
}
+ (UIFont *)jh_systemFontOfSize:(CGFloat)size{
    UIFont *font = [UIFont fontWithName:@"Helvetica-Bold" size:size];
    return font;
}

代码示例


相关文章
|
6月前
|
Linux Shell Windows
Java.Runtime.exec()的使用
Java.Runtime.exec()的使用
32 0
|
安全 Java
高并发编程-Runtime.getRuntime().addShutdownHook为自己的应用添加hook
高并发编程-Runtime.getRuntime().addShutdownHook为自己的应用添加hook
132 0
|
编译器 C语言 iOS开发
Runtime详解及应用
动态语言:编译时确定变量的数据类型。 静态语言:运行时确定变得的数据类型。
327 0
Runtime详解及应用
|
Java Android开发
Eclipse中项目报Target runtime com.genuitec.runtime.generic.jee60 is not defined异常的解决方法
Eclipse中项目报Target runtime com.genuitec.runtime.generic.jee60 is not defined异常的解决
554 0
Eclipse中项目报Target runtime com.genuitec.runtime.generic.jee60 is not defined异常的解决方法
|
设计模式 Java 开发者
Runtime 相关说明 | 学习笔记
快速学习 Runtime 相关说明。
142 0
|
C++
C++ runtime sample
本文演示如何利用函数计算的自定义Runtime功能来运行C++代码
1779 0
|
缓存 iOS开发 编译器
Runtime那些事
Runtime介绍。
2087 0
|
Windows 设计模式
|
存储 JSON 数据格式