运行时简单运用(3.2)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/WangErice/article/details/51242159

在本次分享中,我们针对方法实现的动态替换进行实现,尝试使用简单易于理解的方法来对运行时进行剖析,希望能够对大家有所帮助。假如我们需要动态替换掉某些方法的实现,但是我们不能拿到原始的实现,除了方法名称之外一无所知,下面的方法可能会帮到你。使用替换NSArray方法中的lastObject方法为例进行说明:

方法一:

只针对方法本身的实现进行替换,使用method_setImplementation(Method m, IMP imp)方法:其中:

参数m时需要替换实现的原始方法,imp是替换原始实现的新的方法实现。

id myMethod(idself,SEL _cmd);//声明新的方法实现

id myMethod( NSArray *self,SEL_cmd) {//新的方法实现

    return [selffirstObject];

};

+ (void)load {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        Method orignalMethod = class_getInstanceMethod(self, @selector(lastObject));

        method_setImplementation(orignalMethod, (IMP)myMethod);//为原始的方法绑定新的方法实现

        

    });

}

需要注意的是这种类C的写法,相当于方法的IMP层次的实现,每个方法会有两个默认的参数,一个是参数是(id)self,即调用方法的对象本身,另一个参数是(SEL )_cmd即原始的方法选择器,如果还有其他的显性参数,只需要在参数列表中添加相应的参数即可。例如UILabel类中的-(void)setFont:(UIFont *)font,方法声明时

void _setFont(idself,SEL _cmd, UIFont *font);即可

这种类C写法的好处是,可以在一定程度上减少由于命名冲突而造成的方法的覆盖,避免出现一些不易调试的bug,而且直接调用的就是方法的实现地址,减少了消息传递的层次,提高了运行的效率。

当然也可以使用OC的方法进行实现:

+ (void)load {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        Method orignalMethod = class_getInstanceMethod(self, @selector(lastObject));

        Method newMethod = class_getInstanceMethod(self, @selector(myMethod));

        IMP newImp = method_getImplementation(newMethod);

        method_setImplementation(orignalMethod, newImp);

    });

}

- (id)myMethod {

    return [selffirstObject];

}

方法二:

使用class_addMethod(Class cls, SEL name, IMP imp, const char *types)方法,为方法添加上新的实现,参数cls是需要进行操作的当前类,name是需要替换实现的方法选择器,imp是新的实现,type是方法类型的描述字符串,可以使用(const char *)method_getTypeEncoding(Method m)动态获取,也可以使用手动方式根据方法的参数和返回值类型进行书写点击查看

id myMethod(idself,SEL _cmd);

id myMethod( NSArray *self,SEL_cmd) {

    return [selffirstObject];

};

+ (void)load {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        Method orignalMethod = class_getInstanceMethod(self, @selector(lastObject));

        class_addMethod(self,@selector(lastObject), (IMP)myMethod,method_getTypeEncoding(orignalMethod));

    });

}

方法三:

使用class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)方法,替换掉原始的实现,在正常的使用中,常常将方法二和方法三进行搭配实现,用以达到交换两个方法实现的目的。

id myMethod(idself,SEL _cmd);

id myMethod( NSArray *self,SEL_cmd) {

    return [selffirstObject];

};

+ (void)load {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        Method orignalMethod = class_getInstanceMethod(self, @selector(lastObject));

        class_replaceMethod(self,@selector(lastObject), (IMP)myMethod,method_getTypeEncoding(orignalMethod));

    });

}

方法四:

使用method_exchangeImplementations(Method m1, Method m2)


猜你喜欢

转载自blog.csdn.net/WangErice/article/details/51242159