开发技巧00『 基础知识 』首页投稿(暂停使用,暂停投稿)

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

2016-06-16  本文已影响630人  翟乃玉

猫猫分享,必须精品

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

应用场景

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

方法一:

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

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

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

方法二:

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

分类代码:

@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);

效果:


效果

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

方法三:

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

实现:

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

分类:

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

#import "NSString+NYCategory.h"
#import <objc/message.h>

@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);
效果

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

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

    /**
     *  获取类方法
     *
     *  @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);
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2) 
     __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);

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

上一篇下一篇

猜你喜欢

热点阅读