先介绍下class_addMethod这个fangfa

  1.  
    /**
  2.  
    * Adds a new method to a class with a given name and implementation.
  3.  
    *
  4.  
    * @param cls The class to which to add a method.
  5.  
    * @param name A selector that specifies the name of the method being added.
  6.  
    * @param imp A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd.
  7.  
    * @param types An array of characters that describe the types of the arguments to the method.
  8.  
    *
  9.  
    * @return YES if the method was added successfully, otherwise NO
  10.  
    * (for example, the class already contains a method implementation with that name).
  11.  
    *
  12.  
    * @note class_addMethod will add an override of a superclass's implementation,
  13.  
    * but will not replace an existing implementation in this class.
  14.  
    * To change an existing implementation, use method_setImplementation.
  15.  
    */
  16.  
    OBJC_EXPORT BOOL class_addMethod(Class cls, SEL name, IMP imp,
  17.  
    const char *types)
  18.  
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

这是文档

描述就是:给一个类添加一个新的方法和该方法的具体实现

参数:

第一个

Class cls

cls :你要添加新方法的那个类

第二个

SEL name

name :要添加的方法

第三个

IMP imp

imp:指向实现方法的指针   就是要添加的方法的实现部分

第四个

const char *types

*types:我们要添加的方法的返回值和参数   叫 type encodings 这个东西怎么写我就不说了 可以去查  在这里我有一个懒办法得到它不用暴力手打   往后看

然后这个方法的描述和参数说完了,下面说说他用在哪,

给一个类用运行时添加一个方法   他可以用来解决我们开发中的这个问题------“unrecognized selector sent to instance 0x7faa2a132c0”

在OC中我们调用一个方法时 有个关键字 叫  “消息机制”    就是执行  [receiver message]; 这句代码其实就是发送了一个消息 (发消息的详细过程我就不写了 感兴趣 去查),

消息里面带着你调用这个方法的名称和参数以及是哪个对象发送的消息,然后 发出消息后  如果有对应的方法响应,就执行方法,没有的话就报“unrecognized selector sent to instance 0x7faa2a132c0” ,然后就crash   ,为了防止crash我们可以用class_addMethod给找不到对应方法即将crash的消息添加一个与之对应的方法来防止其因为找不到相应方法而crash

在OC中找不到对相应的实现方法时  有补救机制 即 会先调用动态决议方法   该方法解决不了问题 再调用重定向方法    都解决不了问题是 crash

动态决议方法:

  1.  
    + (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
  2.  
    + (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

重定向方法:

- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

下面上代码:给一个类的对象调用一个未实现的方法  然后用runtime 在动态决议方法中为其添加实现  防止crash

Person类

  1.  
    #import "Person.h"
  2.  
    #import <objc/runtime.h>
  3.  
     
  4.  
    @implementation Person
  5.  
     
  6.  
     
  7.  
    + (BOOL)resolveInstanceMethod:(SEL)sel {
  8.  
    Method exchangeM = class_getInstanceMethod([self class], @selector(eatWithPersonName:));
  9.  
    class_addMethod([self class], sel, class_getMethodImplementation(self, @selector(eatWithPersonName:)),method_getTypeEncoding(exchangeM));
  10.  
    return YES;
  11.  
    }
  12.  
     
  13.  
    - (void)eatWithPersonName:(NSString *)name {
  14.  
    NSLog(@"Person %@ start eat ",name);
  15.  
    }
  16.  
     
  17.  
     
  18.  
     
  19.  
    @end

里面重写resolveInstanceMethod方法  给找不到实现的方法 添加实现  - (void)eatWithPersonName:(NSString *)name;

第一句

Method exchangeM = class_getInstanceMethod([self class], @selector(eatWithPersonName:));

是为下面method_getTypeEncoding(exchangeM) 做铺垫  这样就拿到了eatWithPersonName方法的type encodings 用作class_addMethod的第四个参数,就是上面我提到的不用暴力手打的获取type encodings的方法

然后调用 class_addMethod  为当前类[self class] 的sel 方法 添加实现 class_getMethodImplementation(self, @selector(eatWithPersonName:)) 这一串就是拿到方法eatWithPersonName的IMP指针  然后最后一个参数是  type encodings

然后测试

  1.  
    Person *person = [[Person alloc]init];
  2.  
    //调用Person未实现方法eat
  3.  
    [person performSelector:@selector(eat) withObject:@"minzhe"];

运行结果:

2017-07-14 14:41:35.297 RunTimeAddMethod[1458:379458] Person minzhe start eat 

好了   添加上了    这样就没有 crash

iOS用runtime给一个类动态添加方法 ---class_addMethod的更多相关文章

  1. ios开发runtime学习三:动态添加方法(实际应用少,面试)

    #import "ViewController.h" #import "Person.h" /* 1: Runtime(动态添加方法):OC都是懒加载机制,只要 ...

  2. 使用runtime给类动态添加方法并调用 - class_addMethod

    上手开发 iOS 一段时间后,我发现并不能只着眼于完成需求,利用闲暇之余多研究其他的开发技巧,才能在有限时间内提升自己水平.当然,“其他开发技巧”这个命题对于任何一个开发领域都感觉不找边际,而对于我来 ...

  3. ios开发runtime学习四:动态添加属性

    #import "ViewController.h" #import "Person.h" #import "NSObject+Property.h& ...

  4. 给python类动态添加方法(method)

    群里有人问如何做到 def foo(): pass class Bar(object): pass Bar.set_instance_method(foo) b = Bar() b.foo() 这个其 ...

  5. ios的runtime为什么可以动态添加方法

    一句话概括 每个instance都有一个isa,这个isa,里面含有所有的方法列表,ios提供库函数增加,修改,即实现了动态添加方法

  6. 使用TypeDescriptor给类动态添加Attribute

    给类动态添加Attribute一直是我想要解决的问题,从msdn里找了很久,到Stack Overflow看了不少文章,算是最终有了答案. 先是有这样的一段解释 Attributes are stat ...

  7. iOS运行时使用(动态添加方法)

    1 举例  我们实现一个Person类 然后Person 其实是没得对象方法eat:的 下面调用person的eat方法 程序是会奔溃的 那么需要借助运行时动态的添加方法 Person *p = [[ ...

  8. python装饰器、继承、元类、mixin,四种給类动态添加类属性和方法的方式(一)

    介绍装饰器.继承.元类.mixin,四种給类动态添加类属性和方法的方式 有时候需要給类添加额外的东西,有些东西很频繁,每个类都需要,如果不想反复的复制粘贴到每个类,可以动态添加. # coding=u ...

  9. 快速上手Runtime(四)之动态添加方法

    如果一个类方法非常多,加载类到内存的时候也比较耗费资源,可以使用动态给某个类,添加方法解决.做到优化内存,节省资源的效果. // // Person.m // ResolveInstanceMetho ...

  10. php里面用魔术方法和匿名函数闭包函数动态的给类里面添加方法

    1.认识  __set  (在给不可访问属性赋值时,__set() 会被调用) 也就是说你再访问一个类里面没有的属性,会出发这个方法 class A{ private $aa = '11'; publ ...

随机推荐

  1. 服务器consul与本地服务健康检查不通问题解决

    (125条消息) 服务器consul与本地服务健康检查不通问题解决_向往鸟的博客-CSDN博客_consul健康检查失败 .MathJax, .MathJax_Message, .MathJax_Pr ...

  2. npm不是内部或外部命令,也不是可运行的程序的解决办法

    通常是nodejs没有安装导致 转载https://segmentfault.com/a/1190000023390756 1.Node.js简介 Node.js 是一个基于 Chrome V8 引擎 ...

  3. apk文件结构

    APK (Android Package) 文件,是一个后缀名为.apk的压缩文件,APK文件中包含了一个Android应用程序的所有内容,是Android平台用于安装应用程序的文件. assets  ...

  4. Docker CLI docker buildx 常用命令

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化.Docker是内核 ...

  5. insert image in mail instead of attachment

    https://www.extendoffice.com/documents/outlook/3810-outlook-insert-images-inline.html Go ahead to cl ...

  6. 【git】2.5远程仓库的使用

    资料来源 (1) https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%BF%9C%E7%A8%8B%E4%BB%93%E5%BA%93% ...

  7. PYTHON用户流失数据挖掘:建立逻辑回归、XGBOOST、随机森林、决策树、支持向量机、朴素贝叶斯和KMEANS聚类用户画像|附代码数据

    原文链接:http://tecdat.cn/?p=24346 最近我们被客户要求撰写关于用户流失数据挖掘的研究报告,包括一些图形和统计输出. 在今天产品高度同质化的品牌营销阶段,企业与企业之间的竞争集 ...

  8. h5py学习(一)核心概念

    因pandas的to_hdf5函数有bug TypeError: object of type 'int' has no len(),写dataframe数据出现了报错,遂决定直接使用h5py来写数据 ...

  9. 关于邮箱怎么验证是不是真实的企业邮箱(java汉字和英文呼唤)

    企业邮箱的域名一般都是zhangsan@公司域名,或者zhang_san@公司域名这种形式.这里我只列举zhangsan@公司域名这种形式. 公司要我做一个企业邮箱的模糊匹配和验证,刚接到以为很难.结 ...

  10. java,抽象类,接口的方法,子类继承是不是必须全部实现

    普通类继承,并非一定要重写父类方法. 抽象类继承,如果子类也是一个抽象类,并不要求一定重写父类方法.如果子类不是抽象类,则要求子类一定要实现父类中的抽象方法. 接口类继承.如果是一个子接口,可以扩展父 ...