美文网首页
Swizzling:偷梁换柱的黑魔法

Swizzling:偷梁换柱的黑魔法

作者: 安静等待_ | 来源:发表于2016-10-28 18:33 被阅读13次

    我们知道,OC是一门动态运行时语言。我们也知道,OC中的函数调用本质上其实是消息的发送:objc_MsgSend(someObject, @selector(methodName), parameters)所有要调用的函数,编译阶段是无法确定的,只有到运行的时候才能确定!正因为有此特性,所以在运行阶段,我们都还可以做很多事,而要把本来应该实现的方法A,偷偷换成方法B,便是其中的一种,这种技术叫做:Method Swizzling(方法交换)!

    具体相关的概念就不再啰嗦了,网上都有很多了,可以自行google或者查阅《Effective Objective-C 2.0 编写高质量iOS与OS X 代码的52个有效方法》的第13条,介绍的都比较详细了。这里就总结一下相关的应用!

    调试用

    假如每次调用NSString的lowerCaseString方法时,不要每次都去NSLog,希望直接调用系统的方法时每次都可以输出log,那么这时候就可以用到该技术:

    @interface NSString (XPPMyAdditions)
    
    - (NSString *)xpp_myLowerCaseString;
    
    @end
    
    @implementation NSString (XPPMyAdditions)
    
    - (NSString *)xpp_myLowerCaseString
    {
        NSString *LowerString = [self xpp_myLowerCaseString];
        NSLog(@"%@->%@", self, LowerString);
        return LowerString;
    }
    
    

    接下来做的就是把这个分类里面的方法和原生的方法交换一下:

    void swizzling(){
        Method originalMtd = class_getInstanceMethod([UIF class], @selector(xpp_myLowerCaseString));
        Method swappedMtd = class_getInstanceMethod([NSString class], @selector(lowercaseString));
        method_exchangeImplementations(originalMtd, swappedMtd);
    
    }
    
    

    那么在以后,直接调用系统原生的lowercaseString方法时,实际上调用的是分类里面的方法,在达到原来目的的同时,还能输出结果,非常方便!

    注意:交换过后调用NSString原生的lowerCaseString实际上是调用xpp_myLowerCaseString;而在现在的xpp_myLowerCaseString里面,其实[self xpp_myLowerCaseString]实际上是调用了系统的lowerCaseString方法达到把字符串变为小写的目的。所以,不会陷入死循环!

    一次性更改

    假如今天你接到产品的需求,把App里面所有的字体减小两个点。你怎么办?搜索找工程里面的systemFontOfSize:方法,挨个把字号-2;好,没问题,可以。那第二天她觉得这个字太小了,再加1个点吧^ _ ^。
    这时候,方法交换技术派上用成了:

    @interface UIFont (XppMyAdditions)
    
    + (UIFont *)xpp_systemFontOfSize:(CGFloat)size;
    
    @end
    
    @implementation UIFont (XppMyAdditions)
    
    + (UIFont *)xpp_systemFontOfSize:(CGFloat)size
    {
        UIFont *font = [self xpp_systemFontOfSize:(size-2)];
        NSLog(@"%f---->%f",size, font.pointSize);
        return font;
    }
    

    接下来,再把系统的方法和该方法交换一下:

        Method m1 = class_getClassMethod([UIFont class], @selector(systemFontOfSize:));
        Method m2 = class_getClassMethod([UIFont class], @selector(xpp_systemFontOfSize:));
        method_exchangeImplementations(m1, m2);
    

    注意:这里是类方法!不是实例方法,所以注意API的调用和分类方法要匹配,否则不会报错,但是你会发现没效果诶,这时候就太方便了,随便你想加2个点还是减1个点,无所谓,一个数字的事儿。

    所以,从上看出,方法交换技术还是作用挺大的。只是尽量还是少用,一般就用来调试或者做些需要大量改动的处理。一般代码中不要为了show技术胡乱使用,这样会导致代码结构太差,用的多了,代码可读性也变差了,所以尽量还是少用,要不然哪天出bug了你都不知道问题在哪儿。合理使用即可!

    相关文章

      网友评论

          本文标题:Swizzling:偷梁换柱的黑魔法

          本文链接:https://www.haomeiwen.com/subject/ciyeuttx.html