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 ...
随机推荐
- IEE数据库kill指定条件的进程
需求:IEE数据库临时需要添加一个监控,将command为sleep,time>1800,info为null的进程自动杀掉. 1.杀进程脚本ieekill.sh内容如下 #!/bin/bash ...
- TCP/IP协议(一)
TCP/IP是Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协 ...
- [Architect] ABP(现代ASP.NET样板开发框架) 翻译
所有翻译文档,将上传word文档至GitHub 本节目录: 简介 代码示例 支持的功能 GitHub 简介 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目) ...
- Gradle学习系列之四——增量式构建
在本系列的上篇文章中,我们讲到了如何读懂Gradle的语法,在本篇文章中,我们将讲到增量式地构建项目. 请通过以下方式下载本系列文章的Github示例代码: git clone https://git ...
- ASP.NET的简单与面向对象开发
ASP.NET开发,一开始是为了超赶时间完成任务,只能把功能实现即可.如下面一个功能,在网页中有一个铵钮,用户点一点切换网页的图片,再点一点又切换回来.我们要怎样做?在铵钮事件中去变更图片的路径即可. ...
- 【循序渐进学Python】7.面向对象的核心——类型(上)
我们知道Python是一门面向对象的脚本语言.从C#的角度来看:首先Python支持多继承.Python 类型成员通常都是public的,并且所有成员函数都是virtual的(可以直接重写). 1. ...
- c#重点[集合类型]异常,数组,集合ArrayList,List<>,hashTable,hashtable泛型(Dictionary)
1.foreach[对一些数组或集合进行遍历] foreach(类型 变量名 in 集合对象){语句体} //定义一个数组 ,,,,, }; foreach(var i in sNum1) { Con ...
- Discuz的缓存体系
参考文档:<http://dev.discuz.org/wiki/index.php?title=缓存机制> Discuz中涉及数据缓存的地方有: 1. session Dz的sessio ...
- 树状数组--K.Bro Sorting
题目网址: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110064#problem/D Description Matt’s frie ...
- Java与线程
导语 我们知道,new一个thread,调用它的start的方法,就可以创建一个线程,并且启动该线程,然后执行该线程需要执行的业务逻辑, 那么run方法是怎么被执行的呢? Java线程和os线程 os ...