Runtime 方法替换 和 动态添加实例方法 结合使用
前言:
方法替换,可以替换任意外部类的方法,而动态添加方法只能实现在被添加类创建的对象里,但是将方法替换和动态添加方法结合使用,可以实现,对任意外部类动态添加需要的方法,这个方法可以是类方法也可以是实例方法,这个外部类也可以是没有任何方法声明和实现的类。
主要思路:
使用运行时的方法替换将在外部类将自定义方法hy_resolveInstanceMethod或hy_resolveClassMethod(用hy_前缀表示是我自定义的方法)和需要被添加的类中的resolveInstanceMethod或者resolveClassMethod方法替换,替换之前在hy_resolveInstanceMethod或hy_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 方法替换 和 动态添加实例方法 结合使用的更多相关文章
- ios开发runtime学习三:动态添加方法(实际应用少,面试)
#import "ViewController.h" #import "Person.h" /* 1: Runtime(动态添加方法):OC都是懒加载机制,只要 ...
- ios开发runtime学习四:动态添加属性
#import "ViewController.h" #import "Person.h" #import "NSObject+Property.h& ...
- python 面向对象六 动态添加方法 __slots__限制动态添加方法
一.动态添加属性 >>> class Student(object): pass >>> st = Student() >>> st.name = ...
- Objective-c runtime方法替换引发的死循环
在OC中: API: class_addMethod往一个Class里添加method API: class_getInstanceMethod或class_getClassMethod可以判断某个S ...
- iOS开发Runtime 方法替换
通过#import <objc/runtime.h>我们可以找到: /** * Returns a specified instance method for a given class. ...
- easyui 扩展layout的方法,支持动态添加删除块
$.extend($.fn.layout.methods, { remove: function(jq, region){ return jq.each(function(){ var panel = ...
- Python基础之动态添加属性,方法,动态类,静态类
## 动态添加属性class Person: def __init__(self,name): self.name = name# 1.通过对象.属性名称来操作p = Person('KTModel' ...
- 【17】有关python面向对象编程的提高【多继承、多态、类属性、动态添加与限制添加属性与方法、@property】
一.多继承 案例1:小孩继承自爸爸,妈妈.在程序入口模块再创建实例调用执行 #father模块 class Father(object): def __init__(self,money): self ...
- 第六种方式,python使用cached_property缓存装饰器和自定义cached_class_property装饰器,动态添加类属性(三),selnium webdriver类无限实例化控制成单浏览器。
使用 from lazy_object_proxy.utils import cached_property,使用这个装饰器. 由于官方的行数比较少,所以可以直接复制出来用自己的. class cac ...
随机推荐
- 【转载】Ubuntu下SVN安装和配置
一.SVN安装 1.安装包 1.$ sudo apt-get install subversion 2.创建项目目录 $ sudo mkdir /home/xiaozhe/svn $ cd /home ...
- selenium webdriver (python) 第三版
感谢 感谢购买第二版的同学,谢谢你们对本人劳动成果的支持!也正是你们时常问我还出不出第三版了,也是你们的鼓励,让我继续学习整理本文档. 感谢乙醇前辈,第二版的文档是放在他的淘宝网站上卖的,感谢他的帮忙 ...
- [Python]爬虫v0.1
#coding:utf-8 import urllib ###### #爬虫v0.1 利用urlib2 和 字符串内建函数 ###### # 获取网页内容 def getHtml(url): page ...
- Python函数解析
对于Python的函数,我们需要记住的是: 1. 函数的默认返回值是None. 2. python是一个自上而下逐行解释并执行的语言.因此,函数的定义必须在函数被调用之前.同名的函数,后定义的会覆盖前 ...
- 浅谈DOM性能考虑
浅谈DOM性能考虑 很多人都会忽视脚本对Web应用整体性能的影响.为保证应用的流畅运行,在为文档编写和应用脚本时,需要注意一些问题.一.尽量减少访问DOM和尽量减少标记 访问DOM的方式对脚本性 ...
- 我理解的Android加载器
Android的加载器(loader)是从Android 3.0开始出来的东西.要理解这里需要先理解为什么会出现加载器(也有地方把它说成是装载器)呢? 如果没有加载器... 首先Activity是我们 ...
- JS魔法堂:精确判断IE的文档模式by特征嗅探
一.前言 苦逼的前端攻城狮都深受浏览器兼容之苦,再完成每一项功能前都要左顾右盼,生怕浏览器不支持某个API,生怕原生API内含臭虫因此判断浏览器类型和版本号成了不可绕过的一道关卡,而特征嗅探是继浏览器 ...
- mysql模拟rownum的一个方法
mysql> select * from t2; +----+---------------------+ | id | d | +----+---------------------+ :: ...
- PHP--正则表达式和样式匹配--小记
正则表达式: Regular expression PHP 支持两种风格的函数: POSIX 风格的,有些低版本软件支持,目前高版本的有些已经废弃不用了,比如 zend studio 的较新版本. p ...
- C#开发体感游戏 Kinect应用知识
Kinect首先是一个XBox 360外接体感设备,通过无线方式捕捉动作感知.由PrimeSense提供Range Camera技术,同类产品如任天堂Wii.Play Station Move,必须让 ...

