runtime记录

前言:

最初对于runtime的了解其实只停留在,知道这是一组C的方法,知道消息机制中会把方法调用转成objc_msgSend(theObject,@selector(objectMethod))。随后有一个具体的了解得益于一次尝试,使用runtime解决按钮连续点击限制;这个例子网上有一堆,就不再赘述,但是不得不说,runtime的基本使用都很巧妙的包含其中。也因此,我对runtime的理解更深入了;随后看了runtime的官方文档,知道了原来方法还有很多,但至此,依然不能灵活的运用。真正让我震撼的,是在敲MJExtension的时候runtime的使用灵活而随性,在我看来已经是出神入化(也可能我还没有理解的那么深刻),确实从中学习到很多。

需要知道的概念:

isa指针:

isa指针是每一个对象都会有的,指向这个对象所对应的类,在此要能够区分类和对象的不同;

SEL:

SEL相当于对方法的进一步封装,也可以当做是一个描述,每一个方法都有一个与之对应的SEL类型的数据,根据一个SEL可以找到方法地址,进而调用方法;

其类型定义为:typedef struct object_selector *SEL;

相关使用:SEL sel_1 = @selector(myMethodName:); //把一个方法名包装为一个SEL对象

NSString *str = NSStringFromSelector(sel_1); //得到一个SEL对象的名字;

[object performSelector:sel_1]; //performSelector中其实一直都在使用SEL对象;

Method:

Method是在方法链表中的存在形式,其中有一个SEL类型的selector和一个IMP类型的address,具体来说,就是一个对象的isa指针,指向对象所对应的类结构,而类结构中的参数包括父类、类名、版本信息、类信息、实例大小、实例参数链表、方法链表、方法缓存、协议链表;在方法链表中存储的就是Method;

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY; //isa指针

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE; //父类
    const char *name                                         OBJC2_UNAVAILABLE; //类名
    long version                                             OBJC2_UNAVAILABLE;//版本信息
    long info                                                OBJC2_UNAVAILABLE;//类信息
    long instance_size                                       OBJC2_UNAVAILABLE;//实例大小
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;//实例参数链表
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;//方法链表
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;//方法缓存
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;//协议链表
#endif

} OBJC2_UNAVAILABLE;

  相关方法:class_getInstanceMethod(Class cls, SEL name)  //返回SEL对应的Method对象

IMP:

IMP是指implementation的缩写,是指向方法地址的指针,每一个方法都有一个IMP地址,要注意,并不是只有属性才有地址,方法也有;

相关方法:method_getImplementation(Method m);  //runtime中的方法,返回该方法的IMP类型的方法实现地址;

[object methodForSelector:object_SEL];  //对象可以调用这个封装好的方法直接获得IMP指针;

        [class instanceMethodForSelector:object_SEL];  //上一个方法是实例方法,遍历实例的方法列表返回对应IMP,这个方法是一个类方法,区别在于遍历的是类的方法列表;其实具体实现是一样的;都是通过class_getInstanceMethod进行;

class cache:

分发表:

下面列出一些基本使用;

1、动态操作属性、方法;

属性:

objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

object:表示给那个对象添加属性;

key:属性对应的key值,再添加之后使用这个key来获取属性;

      value: 属性值;

policy:策略枚举;

理解:这个方法可以在你的复制方法中使用,赋值的时候直接关联一个新的属性,使用runtime写在方法内部,但是从表面来看抽象出的方法依然只完成了对于属性赋值,只不过内部的实现不再是 class.aaa = value 这样的语句而已;同时,如果在添加过属性关联之后,想要断开某个属性的关联,直接value传nil即可;

objc_getAssociatedObject(id object, const void *key)

object: 要取的是哪个对象的属性;

key:属性对应的key值;

理解:同上,和普通取值有所不同,但抽象之后依然只是取值,值得注意的是,返回值为id类型;

objc_removeAssociatedObjects(id object)

object:断开所有属性关联的对象;

理解:其实从方法名也可以理解,这个方法用于断开所有关联的属性,会把对象恢复到原始状态;

runtime属性的总结:其实动态的操作属性,就是在进行关联,关联本身就是runtime实现的一部分;我不需要修改类的相关定义,在运行过程中,基于关键字的方式给这个对象增加存储空间;

方法:

class_addMethod(Class cls,  SEL name, IMP imp, const char *types)

cls:给哪个类添加方法;

name: 原有方法的SEL,注意类型为SEL,你希望调用的方法名

imp:新的方法的实现地址,当调用了这个name的方法时,你希望他执行哪一个方法地址;

types:方法描述;

理解:向一个类增加一个方法实现,调用的时候其实还是老的方法名,但是执行的是新的方法实现过程,返回一个BOOL值,表示是否添加成功,其中最后一个参数表示方法的参数以及返回值描述;可使用method_getTypeEncoding(Method m)获得;其实这个方法包含了很多信息,有一个思考点,我们在代码中写了一个方法,但是内部是如何保存的呢?为什么就知道这个方法需要什么参数、什么样的返回值呢?其实这个方法已经比较隐含的表示了这个问题。

class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

理解:替换方法,参数类型同上;

method_exchangeImplementations(Method m1, Method m2)

理解:直接交换两个方法的实现地址,即,当你调用方法m1是,其实对应的是m2的智行过程,反之依然,简单粗暴而有效;

   runtime方法小结:方法的使用一般都放在category里,另外OC中runtime会自动加载load方法,但在Swift中没有实现load方法,可以使用初始化方法;

转载请注明出处,有问题欢迎指出。

时间: 2024-10-03 13:46:21

runtime记录的相关文章

十三、模板设计模式

/* 模板设计模式:实现一个功能时,功能的一部分是确定的,一部分是不确定的,确定的部分还会用到 不确定的部分,那么就把不确定的部分暴露出去,让子类去实现 实现计算一个程序的运行时间: 记录一个开始时间和一个结束时间,两个时间相减就是运行时间 */ abstract class CalTime { public final void runTime() { //记录开始时间 long start=System.currentTimeMillis(); fun(); //记录结束时间 long en

Redmine性能优化方案

近来公司redmine服务器表现很糟糕,在16核,64GRAM的机器上,压测结果竟然只有每秒5~7个请求,部分页面一个都出不来. 以下是我对Redmine性能优化方案: redmine服务器性能问题排查与优化建议: 以下建议的方案是基于redmine运行期的log文件中的render耗时.activerecord耗时,linux系统性能指标采样与 mysql 性能指标采样分析,以及redmine在不同web server下的benchmark而得:   一. 问题排查与定量分析 通过分析redm

常用工具类(System,Runtime,Date,Calendar,Math)

一.Sy 一个java.lang包中的静态工具类. 三大字段: static PrintStream err "标准"错误输出流. static InputStream in "标准"输入流. static PrintStream out "标准"输出流. 其他常用方法: 描述系统信息: 获取系统属性信息: static Properties getProperties(): (Properties是Hashtable的子类,也就是Map 的子类

runtime 任意类型 model 数据库方便存储

//这里边直接上代码 之后我在慢慢地讲解  之后我的QQ:378254160 我有DEMO 方便你们的使用联系我备注 runtime+数据库+任意model类型  当然有时候也是有局限的 //DataBasehandle.m #import "DataBasehandle.h" #import <objc/runtime.h> #import <sqlite3.h> //http://www.sjsjw.com/kf_mobile/article/4_17043

iOS 运行时(runtime)浅析

本博客,直接从分类说起.都知道OC中的分类是不能直接添加属性的,意思间接是能添加属性的.那应该怎么添加呢?那就要用到运行时(runtime)机制. 一,运行时金典用法之一 现在,给HGPerson类增加一个分类:HGPerson+HG.h,给一个属性如下: @property (nonatomic, copy) NSString* name; 貌似,这样写了以后,是能调用的,但是运行就报错了. -[HGPerson setName:]: unrecognized selector sent to

iOS小技巧--用runtime 解决UIButton 重复点击问题

iOS小技巧–用runtime 解决UIButton 重复点击问题 什么是这个问题 我们的按钮是点击一次响应一次, 即使频繁的点击也不会出问题, 可是某些场景下还偏偏就是会出问题. 通常是如何解决 我们通常会在按钮点击的时候设置这个按钮不可点击. 等待0.xS的延时后,在设置回来; 或者在操作结束的时候设置可以点击. - (IBAction)clickBtn1:(UIbutton *)sender { sender.enabled = NO; doSomething sender.enabled

C Run-Time Error R6034问题的解决

1.问题描述 这两天一直在用vs2008编写一个小项目,需要在c++代码中通过命令行的方式调用cl.exe和link.exe,也就是给编译器cl和链接器link传递参数,然后编译链接生成可执行文件exe.最终生成的result.exe运行时老出现Runtime Error R6034 An application has made an attempt to load the C runtime library incorrectly.的错误,围绕这个问题,我查了两天的资料,最后终于解决了..

短信猫信息记录读取程序

有二年多时间没有写程序了写起程序太陌生了要求写一个短信猫信息记录的读取程序买了个短信猫下载了一个动态链接库sms.dll依据所给案例写了一个运行比较稳定. using System;using System.Drawing;using System.Collections;using System.ComponentModel;using System.Windows.Forms;using System.Data;using System.Runtime.InteropServices;usi

android的入门记录(一)

---恢复内容开始--- 首先,这是我人生中的第一篇博客,也许严格意义上它并不算是一篇博客,但也代表着一些东西. 前言 我们往往在开始学习一门新的语言或者课程时会遇见各式各样的问题,比如说:环境搭建遇到问题,资源不知道去哪里下载,代码令人无法下手,甚至不知道如何运行. 于是便产生了这样的一篇文章--关于我Android入门的记录,以及各式各样问题的解决. 首先从资源的寻找说起. 第一节 开发环境的搭建 Android开发首先需要搭建运行环境,它们分别为 1.JDK:Java开发工具包,因为安卓使