前言:

方法替换,可以替换任意外部类的方法,而动态添加方法只能实现在被添加类创建的对象里,但是将方法替换和动态添加方法结合使用,可以实现,对任意外部类动态添加需要的方法,这个方法可以是类方法也可以是实例方法,这个外部类也可以是没有任何方法声明和实现的类。

主要思路:

使用运行时的方法替换将在外部类将自定义方法hy_resolveInstanceMethodhy_resolveClassMethod(用hy_前缀表示是我自定义的方法)和需要被添加的类中的resolveInstanceMethod或者resolveClassMethod方法替换,替换之前在hy_resolveInstanceMethodhy_resolveClassMethod方法内部写好本应该在resolveInstanceMethod或者resolveClassMethod方法内部写好的runtime动态添加方法的逻辑。

可能有点绕,不过至少需要继续阅读源码,思考其中的逻辑,其实不难,前提是熟悉使用runtime的方法。

缺陷:1、含参数的方法难以处理,参数值需要根据实际业务逻辑而定。

Before use import <objc/message.h> ,need following:

Create Person.h and Person.m

Person.h:

 #import <Foundation/Foundation.h>

 @interface Person : NSObject

 @end

Person.m:

 #import "Person.h"

 @implementation Person

 @end

Create OtherPerson.h and OtherPerson.m

OtherPerson.h:

 #import <Foundation/Foundation.h>

 @interface OtherPerson : NSObject

 @end

OtherPerson.m:

 //
// Created by HEYANG on 16/1/11.
// Copyright © 2016年 HEYANG. All rights reserved.
// #import "OtherPerson.h"
#import <objc/message.h> @implementation OtherPerson +(void)load{
Class clazz = NSClassFromString(@"Person"); //获取替换前的类方法
Method instance_eat =
class_getClassMethod(clazz, @selector(resolveInstanceMethod:));
//获取替换后的类方法
Method instance_notEat =
class_getClassMethod(self, @selector(hy_resolveInstanceMethod:)); //然后交换类方法
method_exchangeImplementations(instance_eat, instance_notEat); //获取替换前的类方法
Method class_eat =
class_getClassMethod(clazz, @selector(resolveClassMethod:));
//获取替换后的类方法
Method class_notEat =
class_getClassMethod(self, @selector(hy2_resolveClassMethod:)); //然后交换类方法
method_exchangeImplementations(class_eat, class_notEat); } void eat_1(id self,SEL sel)
{
NSLog(@"到底吃不吃饭了");
NSLog(@"%@ %@",self,NSStringFromSelector(sel));
}
void eat_2(id self,SEL sel, NSString* str1,NSString* str2)
{
NSLog(@"到底吃不吃饭了");
NSLog(@"%@ %@",self,NSStringFromSelector(sel));
NSLog(@"打印两个参数值:%@ and %@",str1,str2);
} +(BOOL)hy_resolveInstanceMethod:(SEL)sel{
//当sel为实现方法中 有 eat 方法
if (sel == NSSelectorFromString(@"eat")) {
//就 动态添加eat方法 // 第一个参数:给哪个类添加方法
// 第二个参数:添加方法的方法编号
// 第三个参数:添加方法的函数实现(函数地址)
// 第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd
class_addMethod(self, sel, (IMP)eat_1, "v@:");
}
return YES;
}
+(BOOL)hy2_resolveClassMethod:(SEL)sel{ if (sel == NSSelectorFromString(@"eat:with:")) { class_addMethod(objc_getMetaClass("Person"), sel, (IMP)eat_2, "v#:@@");
} return YES;
} @end

last In file ‘main.m’:

main.m:

 /**
*
* Swap Method and Dynamic add Method (交换方法和动态添加方法)
*
*/ #import <Foundation/Foundation.h> //ignore undeclared warm 忽视未声明的警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector" int main(int argc, const char * argv[]) {
@autoreleasepool {
//get this Person class 拿到了这个Person类
Class clazz = NSClassFromString(@"Person");
//get this Person Instance 拿到这个Person实例
id person = [[clazz alloc] init]; //send message to 'eat' method in Person Class or Person Instance
//发送消息给Person类或者Person实例的‘eat’方法 不含参数
[person performSelector:@selector(eat) withObject:nil];
//发送消息给Person类的‘eat’方法 含两个参数
[clazz performSelector:@selector(eat:with:)
withObject:@"Hello"
withObject:@"World"];
}
return ;
} #pragma clang diagnostic pop

the code test result

Runtime 方法替换 和 动态添加实例方法 结合使用的更多相关文章

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

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

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

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

  3. python 面向对象六 动态添加方法 __slots__限制动态添加方法

    一.动态添加属性 >>> class Student(object): pass >>> st = Student() >>> st.name = ...

  4. Objective-c runtime方法替换引发的死循环

    在OC中: API: class_addMethod往一个Class里添加method API: class_getInstanceMethod或class_getClassMethod可以判断某个S ...

  5. iOS开发Runtime 方法替换

    通过#import <objc/runtime.h>我们可以找到: /** * Returns a specified instance method for a given class. ...

  6. easyui 扩展layout的方法,支持动态添加删除块

    $.extend($.fn.layout.methods, { remove: function(jq, region){ return jq.each(function(){ var panel = ...

  7. Python基础之动态添加属性,方法,动态类,静态类

    ## 动态添加属性class Person: def __init__(self,name): self.name = name# 1.通过对象.属性名称来操作p = Person('KTModel' ...

  8. 【17】有关python面向对象编程的提高【多继承、多态、类属性、动态添加与限制添加属性与方法、@property】

    一.多继承 案例1:小孩继承自爸爸,妈妈.在程序入口模块再创建实例调用执行 #father模块 class Father(object): def __init__(self,money): self ...

  9. 第六种方式,python使用cached_property缓存装饰器和自定义cached_class_property装饰器,动态添加类属性(三),selnium webdriver类无限实例化控制成单浏览器。

    使用 from lazy_object_proxy.utils import cached_property,使用这个装饰器. 由于官方的行数比较少,所以可以直接复制出来用自己的. class cac ...

随机推荐

  1. 【转载】Ubuntu下SVN安装和配置

    一.SVN安装 1.安装包 1.$ sudo apt-get install subversion 2.创建项目目录 $ sudo mkdir /home/xiaozhe/svn $ cd /home ...

  2. selenium webdriver (python) 第三版

    感谢 感谢购买第二版的同学,谢谢你们对本人劳动成果的支持!也正是你们时常问我还出不出第三版了,也是你们的鼓励,让我继续学习整理本文档. 感谢乙醇前辈,第二版的文档是放在他的淘宝网站上卖的,感谢他的帮忙 ...

  3. [Python]爬虫v0.1

    #coding:utf-8 import urllib ###### #爬虫v0.1 利用urlib2 和 字符串内建函数 ###### # 获取网页内容 def getHtml(url): page ...

  4. Python函数解析

    对于Python的函数,我们需要记住的是: 1. 函数的默认返回值是None. 2. python是一个自上而下逐行解释并执行的语言.因此,函数的定义必须在函数被调用之前.同名的函数,后定义的会覆盖前 ...

  5. 浅谈DOM性能考虑

    浅谈DOM性能考虑 很多人都会忽视脚本对Web应用整体性能的影响.为保证应用的流畅运行,在为文档编写和应用脚本时,需要注意一些问题.一.尽量减少访问DOM和尽量减少标记    访问DOM的方式对脚本性 ...

  6. 我理解的Android加载器

    Android的加载器(loader)是从Android 3.0开始出来的东西.要理解这里需要先理解为什么会出现加载器(也有地方把它说成是装载器)呢? 如果没有加载器... 首先Activity是我们 ...

  7. JS魔法堂:精确判断IE的文档模式by特征嗅探

    一.前言 苦逼的前端攻城狮都深受浏览器兼容之苦,再完成每一项功能前都要左顾右盼,生怕浏览器不支持某个API,生怕原生API内含臭虫因此判断浏览器类型和版本号成了不可绕过的一道关卡,而特征嗅探是继浏览器 ...

  8. mysql模拟rownum的一个方法

    mysql> select * from t2; +----+---------------------+ | id | d | +----+---------------------+ :: ...

  9. PHP--正则表达式和样式匹配--小记

    正则表达式: Regular expression PHP 支持两种风格的函数: POSIX 风格的,有些低版本软件支持,目前高版本的有些已经废弃不用了,比如 zend studio 的较新版本. p ...

  10. C#开发体感游戏 Kinect应用知识

    Kinect首先是一个XBox 360外接体感设备,通过无线方式捕捉动作感知.由PrimeSense提供Range Camera技术,同类产品如任天堂Wii.Play Station Move,必须让 ...