zoukankan      html  css  js  c++  java
  • 方法混合(Method Swizzling):动态替换已有类的方法

       动态替换类的方法在不能改变原有代码的情况下,提供了一种解决方法。貌似这种方法不太常用,不过记下来以备后患~。

      功能:用这种方法可以给你的程序提供一些一般方法不能实现的功能。

      例子:UIWebView的delegate接口提供了一个shouldStartLoadWithRequest()方法,可以通过NSURLRequest这个对象得到所要装载网页 的详情(head头信息等),但你不能修改这个对象(添加或修改你需要的HTTP请求头信息,比如:“User-Agent”字段),如果HTTP请求的对端,(比如硬件设备)需要各种特殊的头信息,将束手无策。

    但如果使用方法混合(Method Swizzling)计数就可以实现动态修改接受类的方法。

      注意:技术比较强大,但比较危险(具体还未知。。。待确定)

      实现:(以代码为例子)将SimpleClass类的print方法动态替换成Swizzle类的swizzlePrint方法:

    //Swizzle.h
    #import <Foundation/Foundation.h>
    @interface Swizzle : NSObject {
    }
    + (BOOL)swizzle:(Class)c1 oSelector:(SEL)orig Class:(Class)c2 aSelector:(SEL)newSel;
    - (void)testSwizzle;
    @end
    
    //Swizzle.m
    #import "Swizzle.h"
    #import <objc/runtime.h>
    #import <objc/message.h>
    
    @interface SimpleClass : NSObject {
    }
    - (void)print:(NSString *)str;
    @end
    
    @implementation SimpleClass
    /*the old method to replace*/
    - (void)print:(NSString *)str {
        NSLog(@"Input String is : %@", str);
    }
    @end
    
    @implementation Swizzle
    
    /*****************************************************************************
     功能描述  : 将类c1中方法orig的实现替换为类c2中方法newSel的实现
     输入参数  : (Class)c1
                 (SEL)orig
                 (Class)c2
                 (SEL)newSel
     返 回 值  : BOOL
    *****************************************************************************/
    + (BOOL)swizzle:(Class)c1 oSelector:(SEL)orig Class:(Class)c2 aSelector:(SEL)newSel{
        /*注意区分实例方法和类方法:实例方法用getInstanceMethod,类方法:getClassMethod*/
        Method origMethod = class_getInstanceMethod(c1, orig);
        Method newMethod = class_getInstanceMethod(c2, newSel);
        
        if (NULL == origMethod)
        {
            NSLog(@"can't find orig method %@ in class %@",NSStringFromSelector(origMethod),c1);
            return NO;
        }
        if (NULL == newMethod)
        {
            NSLog(@"can't find new method %@ in class %@",NSStringFromSelector(newSel),c2);
            return NO;
        }
        
        /*class_addMethod:add a new method to a class with a given name and implementation(详见官方文档)*/
        BOOL added = class_addMethod(c1, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
        
        if(added)
        {
            /*if added success just replace :NO TEST---MAY HAVE SOME PROBLEM*/
            class_replaceMethod(c1, newSel, method_getImplementation(origMethod)), method_getTypeEncoding(origMethod));
        }else
        {
            /*change two method's implementation*/
            method_exchangeImplementations(origMethod, newMethod);
        }
        return YES;
    }
    /*The new method*/
    - (void)swizzlePrint:(NSString *)str {
        NSLog(@"After Swizzle:%@",str);
    }
    /*a test method*/
    - (void)testSwizzle {
        SEL oriSel = @selector(print:);
        SEL newSel = @selector(swizzlePrint:);
        
        SimpleClass *simple = [[SimpleClass alloc] init]];
        [simple print:@"Hello World"];
        
        [Swizzle swizzle:[simple class] oSelector:oriSel Class:[self class] aSelector:newSel];
        [simple print:@"Hello World"];
        
        [simple release];
    }
  • 相关阅读:
    winform中文本框添加拖拽功能
    jQuery返回顶部代码
    判断IP地址是否在指定范围内的方法
    jQuery提示通知插件jBox
    Windows 8.1 SecureBoot未正确配置的解决方法
    操作系统下载
    js中(function(){…})()立即执行函数写法理解
    。net MVC 序列化 反序列化
    js点击button按钮跳转到页面代码
    单例模式
  • 原文地址:https://www.cnblogs.com/kelisi-king/p/3238798.html
Copyright © 2011-2022 走看看