猫猫学iOS之RunTime运用方法交换

猫猫分享,必须精品

原创文章,欢迎转载。转载请注明:翟乃玉的博客
地址:http://www.jianshu.com/notebooks/4236923/latest

应用场景

在iOS开发当中,我们经常会用一些常用的系统写方法,但是有时候这些方法让我们并不满意,比如说我切割字符串,系统有个方法是如下
- (NSString *)substringFromIndex:(NSUInteger)from;切割一串字符串(self)从第from个字符开始到最后,返回值是切割好的字符串
比如,我想将字符串@"123456789"从第二个字符串切割,然后打印出来,这时候我可以通过下面的几种方法解决。

方法一:

最简单最直接的方法,上代码:

NSString *str = [@"123456789" substringFromIndex:2];
NSLog(@"str = %@",str);

效果:
猫猫学iOS之RunTime运用方法交换_第1张图片
效果

简单粗暴,但是这个仅限于此场景,如果我想对截取后的字符做更多操作,需要每个地方都这么写,会有很多重复代码。

方法二:

运用分类技术,自己写方法来实现

分类代码:

@interface NSString (NYCategory)
- (NSString *)ny_substringFromIndex:(NSUInteger)from;
@end

@implementation NSString (NYCategory)

-(NSString *)ny_substringFromIndex:(NSUInteger)from{
    NSString *subStr = [self substringFromIndex:from];
    NSLog(@"截取后的字符串是 %@",subStr);
    return subStr;
}
@end

调用:

//首先导入分类
#import "NSString+NYCategory.h"
//调用
NSString *str = [@"123456789" ny_substringFromIndex:2];
NSLog(@"str = %@",str);

效果:


猫猫学iOS之RunTime运用方法交换_第2张图片
效果

这种方法可以做更多的事情,比如我想在切割的时候把当前字符串赋值成切割好的字符串,或者说给切割的字符串去掉空格等等,总之,没有做不到 只有想不到。

  • 但是他还是有一定的缺点:
    1 对导入分类有着很高的依赖,每次用这个方法我必须都要导入自己的分类。
    2 方法名不能跟系统的一样,有时候我们就像用系统的,并且还就是想要新东西(他喵的你有病吧。。。),于是最开始我很天真的定义分类用系统的方法名,然后调用,然后就悲剧了,如下:


    猫猫学iOS之RunTime运用方法交换_第3张图片

    很容易造成了递归死循环。。。然后改成super,更悲剧了,你懂的,分类根本没有super这一说,好吧,那就用定义NSString的子类,重写方法,然后调用super。。。(我觉得问这问题的人真的有病。。。)

方法三:

方法三就是运用运行时的交换方法的手段来改进方法二的两个缺点,简单说,就是我又不想导入分类,也不想定义子类,然后还想用系统NSString的方法名,就原来怎么用我现在就怎么用,还想要这样的效果。有这样的好事嘛?有 RunTime...(这东西感觉基本就是为了面试官而存在的)

实现:

实现起来还是用分类,与之不同的是我们需要用到类加载方法和runtime的方法交换函数method_exchangeImplementations

分类:

@interface NSString (NYCategory)
- (NSString *)ny_substringFromIndex:(NSUInteger)from;
@end

#import "NSString+NYCategory.h"
#import 

@implementation NSString (NYCategory)
// 当程序一运行,所有类会被加载,这时候会调用这个方法
+ (void)load{

    //class_getInstanceMethod是获取类的对象的方法
    Method subStrMethod = class_getInstanceMethod([NSString class], @selector(substringFromIndex:));
    
    Method ny_subStrMethod = class_getInstanceMethod([NSString class], @selector(ny_substringFromIndex:));
    
    // 交换方法实现
    method_exchangeImplementations(subStrMethod, ny_subStrMethod);
    
}

-(NSString *)ny_substringFromIndex:(NSUInteger)from{
    NSString *subStr = [self ny_substringFromIndex:from];
    NSLog(@"截取后的字符串是 %@",subStr);
    return subStr;
}

调用:

    NSString *str = [@"123456789" substringFromIndex:2];
    NSLog(@"str = %@",str);
猫猫学iOS之RunTime运用方法交换_第4张图片
效果

在这里调用的时候我们并没有导入分类,用的方法名也是系统的,但是效果却可以做到方法二的效果。

原理:在运行的时候,当分类被加载(load方法执行)的时候,用到了运行时的交换方法实现的机制,对方法名和实现进行了对调,这里我们需要明白下面的概念:

  • 一个方法包括了 方法名方法实现
  • 方法名: 「类型是Method」可以通过运行时的方法获取到。
    1 class_getInstanceMethod 获取对象方法的方法编号。这里可以自己用command键点进去看看系统里的,他的返回值类型是
    Method**类型。
    2 class_getClassMethod 获取类方法的方法编号。
  • 方法实现: 也就是方法具体要做的事情「类型是IMP」可以通过运行时的方法class_getMethodImplementation获取到。
    /**
     *  获取类方法
     *
     *  @param cls  Class:获取哪个类方法
     *  @param name SEL:获取方法编号,根据SEL就能去对应的类找方法
     *
     *  @return  Method 类方法名
     */
    OBJC_EXPORT Method class_getClassMethod(Class cls, SEL name)
    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
    
    /**
     *  获取对象方法
     *
     *  @param cls  Class:获取哪个类方法
     *  @param name SEL:获取方法编号,根据SEL就能去对应的类找方法
     *
     *  @return  Method 对象方法名
     */
    OBJC_EXPORT Method class_getInstanceMethod(Class cls, SEL name)
    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
    
    /**
     *  获取方法实现
     *
     *  @param cls  Class:获取哪个类方法
     *  @param name SEL:获取方法编号,根据SEL就能去对应的类找方法
     *
     *  @return  IMP 方法实现
     */
    OBJC_EXPORT IMP class_getMethodImplementation(Class cls, SEL name)
    __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
  • 交换方法
    对两个方法名的方法实现进行对调,在运行的时候,当调用方法时(perform之类的),原来的时候,我们调用@selector(substringFromIndex:)方法,他会自己找到他的实现,运行,但是当我们对调之后,调用@selector(substringFromIndex:)会运行@selector(ny_substringFromIndex:)的实现
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2) 
     __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);

不知道当你看到这些的时候有没有想起猫之前说的指向指针的指针,表示类的类,哈哈,这玩意我想到的是指向方法的指针,总之,先这么理解吧,欢迎大家给猫猫指正,猫本身是体育生,没有上过计算机的专业课,一路磕磕绊绊连蒙带猜就靠各位朋友指点教育批评才混过来的,有错误地方欢迎指正哈,设计底层的东西猫是真瞎。。。

你可能感兴趣的:(猫猫学iOS之RunTime运用方法交换)