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 ...
随机推荐
- windows下面go语言环境搭建
步骤一:golang下载 下载地址是:http://www.golangtc.com/download 下载完成之后解压缩,放到你的c:/根目录下面.然后配置一下环境变量! 环境变量配置如下: 1.新 ...
- iOS-UIScrollView-图片缩放
一. 实现功能 两个手指捏合,可以放大或者缩小图片. 二.原理说明 1. 实现缩放功能的四个步骤 (1) 让控制器遵守代理协议 (2) 让scrollView设置代理 self (3) 调用代理方法, ...
- UPW学习资料整理 .NET C# 转
开发工具下载https://www.visualstudio.com/?Wt.mc_id=DX_MVP5000319 Windows 10 UWP开发视频1http://blogs.windows.c ...
- 谈Mysql索引
myisam和innodb的索引有什么区别? 两个索引都是B+树索引,但是myisam的表存储和索引存储是分开的,索引存储中存放的是表的地址.而innodb表存储本身就是一个B+树,它是用主键来做B+ ...
- codevs4247奇特的生物 解析报告
4247 奇特的生物 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 科学家们最近发现了一种奇怪的生物,它们每天长大一岁 ...
- nodejs+express+jade给我baby做个小相册
去年年底迎来了my little star.从此人生多了一个最重要的牵挂.生了宝宝全家人都太忙了.最近宝宝稍微大点了,终于有空可以研究下技术了.这是14年第一帖.废话不多了.开始吧 1.安装NTVS ...
- WPF Control Hints - TabControl : 怎么修改整个tab header的margin?
WFP里面TabControl我们可以添加多个TabItem,每个TabItem的Header就是我们常点击的tab标签.但是默认的layout行为里面,这个header是有个2个像素的margin, ...
- C#设计模式——单件模式(Singleton Pattern)
一.概述在软件开发过程中,我们有时候需要保证一个类仅有一个实例,比如在一个电脑用户下只能运行一个outlook实例.这时就需要用到单件模式.二.单件模式单件模式保证一个类仅有一个实例,并提供一个访问它 ...
- ext 树节点操作
ext 树节点操作 tree :树 node:节点 1.全部展开 tree.expandAll(); 2.全部收缩 tree.collapseAll(); 3.得到父节点 node.parent ...
- MySQL服务器权限表
MySQL服务器通过权限表来控制用户对数据库的访问,权限表存放在mysql数据库里,由mysql_install_db脚本初始化.这些权限表分别user,db,table_priv,columns_p ...

