zoukankan      html  css  js  c++  java
  • Swizzle在OC问题排查中的应用

    原博文https://newrelic.com/blog/best-practices/right-way-to-swizzle

    1 、Swizzling是通过使用另一个方法替换该方法的实现来更改方法功能的行为,通常是在运行时。使用swizzling有许多不同的原因:内省、重写默认行为,甚至可能是动态方法加载。我看到很多博客文章讨论Objective-C中的swizzling,其中很多都推荐了一些非常糟糕的做法。如果您正在编写独立的应用程序,这些糟糕的做法其实并不是什么大问题,但是如果您正在为第三方开发人员编写框架,swizzling可能会打乱一些保持一切顺利运行的基本假设。那么,在Objective-C中使用swizzle的正确方法是什么?
    让我们从基础开始。当我说swizzling时,我指的是用我自己的方法替换原始方法的行为,通常是从替换方法中调用原始方法。Objective-C允许使用Objective-C-runtime提供的函数执行此操作。在运行时,Objective-C方法表示为一个名为Method的C结构;

    2、知识点

    SEL : 类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是方法编号。其中@selector()是取类方法的编号,取出的结果是SEL类型,SEL methodId = @selector(func);

    IMP:一个函数指针,保存了方法的地址

    -(void)addNewMethod:(NSString *)str{}
    
    取得SEL的方法
    
    SEL sel = @selector(addNewMethod:);
    
    取得方法名(编号)
    
     NSString *methodName1 = NSStringFromSelector(@selector(addNewMethod:));
    
    取得IMP指针
    
    IMP imp = [self methodForSelector:@selector(addNewMethod:)]
    或者
    IMP imp = [NSObject instanceMethodForSelector:@selector(addNewMethod:)]
    3 、相关的API:
    利用method_exchangeImplementations来交换2个方法中的IMP。
    利用 class_replaceMethod来修改类。
    利用 method_setImplementation来直接设置某个方法的IMP。
    方法交换类的实现:
    /** 
     * Sets the implementation of a method.
     * 
     * @param m The method for which to set an implementation.
     * @param imp The implemention to set to this method.
     * 
     * @return The previous implementation of the method.
     */
    OBJC_EXPORT IMP _Nonnull
    method_setImplementation(Method _Nonnull m, IMP _Nonnull imp) 
        OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
    
    /** 
     * Exchanges the implementations of two methods.
     * 
     * @param m1 Method to exchange with second method.
     * @param m2 Method to exchange with first method.
     * 
     * @note This is an atomic version of the following:
     *  code 
     *  IMP imp1 = method_getImplementation(m1);
     *  IMP imp2 = method_getImplementation(m2);
     *  method_setImplementation(m1, imp2);
     *  method_setImplementation(m2, imp1);
     *  endcode
     */
    OBJC_EXPORT void
    method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2) 
        OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
    method_exchangeImplementations就相当于调用了两次method_setImplementation
    4、下边是替换测试demo:
    #import "ViewController.h"
     #import <objc/message.h>
    @interface ViewController ()
    - (void) swizzleExample;
    - (int) originalMethod;
    @end
    
    static IMP __original_Method_Imp;
    int _replacement_Method(id self, SEL _cmd)//参数没有也行,所有的OC方法传递了两个隐藏的参数:对self的引用(id self),和方法名selector(SEL _cmd)
    {

         assert([NSStringFromSelector(_cmd) isEqualToString:@"originalMethod"]);cmd是

    originalMethod,这里没有跳断言。所以我们改变的只是IMP

        printf("2222222222");
        return 2;
    }
    
    
    
    
    @implementation ViewController
    
    - (void) swizzleExample //call me to swizzle
    {
        Method m = class_getInstanceMethod([self class],
    @selector(originalMethod));
    
        __original_Method_Imp = method_setImplementation(m,
    (IMP)_replacement_Method);//单边替换
    }
    
    - (int) originalMethod
    {
           
         printf("11111111111");
           return 1;
    }
    
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
       
        int originalReturn = [self originalMethod];
        [self swizzleExample];
        int swizzledReturn = [self originalMethod];//最终调用的是22222
        assert(originalReturn == 1); //true
        assert(swizzledReturn == 2); //true
    }
    
    
    @end
     
  • 相关阅读:
    jQuery选择器---层次选择器总结
    jQuery选择器---基本选择器总结
    jQuery手风琴
    jQuery(ajax)的使用方法
    css 3d 基础知识
    Android Dynamic Action(动态Action)—像访问网页一样地访问Activity
    笨鸟不乖 是这么设计Android项目架构的
    Android Auto Scroll ViewPager (Smooth)
    [原创] 在线音乐API的研究 (Part 2.1)
    [原创] 浅谈开源项目Android-Universal-Image-Loader(Part 3.1)
  • 原文地址:https://www.cnblogs.com/8335IT/p/15501450.html
Copyright © 2011-2022 走看看