Runtime 方法替换 和 动态添加实例方法 结合使用

前言:

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

主要思路:

使用运行时的方法替换将在外部类将自定义方法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:

1 #import <Foundation/Foundation.h>
2
3 @interface Person : NSObject
4
5 @end

Person.m:

1 #import "Person.h"
2
3 @implementation Person
4
5 @end

Create OtherPerson.h and OtherPerson.m

OtherPerson.h:

1 #import <Foundation/Foundation.h>
2
3 @interface OtherPerson : NSObject
4
5
6 @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 0;
}

#pragma clang diagnostic pop

the code test result

extra

download

download github code source

时间: 2025-01-21 05:37:45

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

jQuery移除tr无效的解决方法(tr是动态添加)_jquery

今天在做项目时,碰到一个问题,那就是移除掉某些tr(tr是动态添加的).尝试了很多方法,都不见效(比如,deleteRow方法,貌似传的参数只能是tr的行数.没有仔细研究目前).后来,发现这个方法效果不错,特此记录. $(temp).parent().remove(); //temp为td的id code class="js plain"> 我的理解是这样的:$(temp)先获取到该td对象,然后.parent()获取到td的tr,再remove()方法,删除tr.</co

多种方法实现JS动态添加事件_javascript技巧

方法一.setAttribute var obj = document.getElementById("obj"); obj.setAttribute("onclick", "javascript:alert('测试');"); 但是IE不支持用 setAttribute 设置某些属性,包括对象属性.集合属性.事件属性,也就是说用 setAttribute 设置 style.onclick.onmouseover 这些属性在 IE 中是行不通的.

asp.net为网页动态添加关键词的方法

  asp.net为网页动态添加关键词的方法          这篇文章主要介绍了asp.net为网页动态添加关键词的方法,可实现动态添加keyword meta的功能,非常具有实用价值,需要的朋友可以参考下.具体如下: 这段代码可以修改网页的keyword meta ? 1 2 3 4 HtmlMeta keywords = new HtmlMeta(); keywords.Name = "keywords"; keywords.Content = "关键词";

JavaScript动态添加列的方法_javascript技巧

本文实例讲述了JavaScript动态添加列的方法.分享给大家供大家参考.具体实现方法如下: /*** * 动态添加table 列 * @param result */ function addRow(resultJson){ /* var temp = []; temp = $.grep(arr, function(val, key) { if(val.indexOf('c') != -1) return true; // 如果[invert]参数不给或为false, $.grep只收集回调函

jQuery动态添加删除select项(实现代码)_jquery

复制代码 代码如下: // 添加function col_add() { var selObj = $("#mySelect"); var value="value"; var text="text"; selObj.append("<option value='"+value+"'>"+text+"</option>");}// 删除function col_d

JQuery动态添加和删除表格行的方法

 这篇文章主要介绍了JQuery动态添加和删除表格行的方法,实例分析了jQuery中动态操作表格行的技巧,具有一定参考借鉴价值,需要的朋友可以参考下     本文实例讲述了JQuery动态添加和删除表格行的方法.分享给大家供大家参考.具体分析如下: 昨天做页面表格行动态添加和删除,看了无数的介绍,发现了一个好东东,JQuery.用它实现起来还真的是很方便,这个是我用到我们平台的一个方法. 代码如下: //记录添加行数 var areaCount=1; //记录实际表格行数 var rowCoun

javascript的document中的动态添加标签实现方法_javascript技巧

document的高级篇中提供了节点操作的函数,具体包括:获取节点,改变节点,删除节点,替换节点,创建节点,添加节点,克隆节点等函数.我们可以利用这些函数动态改变html的节点. 1.JavaScript <script type="text/javascript"> function test1(){//对个节点的ID相同时候的情况 var myhref = document.getElementById('same'); window.alert(myhref.inne

JQuery动态添加和删除表格行的方法_jquery

本文实例讲述了JQuery动态添加和删除表格行的方法.分享给大家供大家参考.具体分析如下: 昨天做页面表格行动态添加和删除,看了无数的介绍,发现了一个好东东,JQuery.用它实现起来还真的是很方便,这个是我用到我们平台的一个方法. 复制代码 代码如下: //记录添加行数 var areaCount=1; //记录实际表格行数 var rowCount=1; //删除模板html var delRowTemplete = "<td><a href='javascript:voi

javascript动态添加、修改、删除对象的属性与方法详解_javascript技巧

现在介绍如何为一个对象添加.修改或者删除属性和方法.在其他语言中,对象一旦生成,就不可更改了,要为一个对象添加修改成员必须要在对应的类中修改,并重新实例化,而且程序必须经过重新编译.JavaScript 中却非如此,它提供了灵活的机制来修改对象的行为,可以动态添加.修改.删除属性和方法.例如首先使用类Object来创建一个空对象user:var user=new Object(); 1.添加属性这时user 对象没有任何属性和方法,显然没有任何用途.但可以为它动态的添加属性和方法,例如:user