美文网首页ios底层原理
iOS Method Swizzle的一些坑

iOS Method Swizzle的一些坑

作者: saber_zz | 来源:发表于2018-05-23 20:21 被阅读0次

我们常用的swizzle用法如下:

BOOL simple_Swizzle(Class aClass, SEL originalSel,SEL swizzleSel){
    
    Method originalMethod = class_getInstanceMethod(aClass, originalSel);
    Method swizzleMethod = class_getInstanceMethod(aClass, swizzleSel);
    method_exchangeImplementations(originalMethod, swizzleMethod);
    
    return YES;
}
BOOL best_Swizzle(Class aClass, SEL originalSel,SEL swizzleSel){
    
    Method originalMethod = class_getInstanceMethod(aClass, originalSel);
    Method swizzleMethod = class_getInstanceMethod(aClass, swizzleSel);
    BOOL didAddMethod = class_addMethod(aClass, originalSel, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    if (didAddMethod) {
        class_replaceMethod(aClass, swizzleSel, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    }else{
        method_exchangeImplementations(originalMethod, swizzleMethod);
    }
    
    return YES;
}

我们分别用这俩种方法来测试下面的3中情况

swizzle一个父类的方法

我们新建一个Father类

@interface Father : NSObject
  - (void)work;
@end
 @implementation Father
- (void)work{
  NSLog(@"father work");
}
@end

Son类

@interface Son : Father
@end

@implementation Son
@end

simple_Swizzle

+ (void)load{
    simple_Swizzle(self,@selector(work), @selector(son_work));
}

- (void)son_work{
   NSLog(@"son_category work") ;
    [self son_work];
  }

调用[[Father new] work]报错
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Father son_work]: unrecognized selector sent to instance 0x60c0000140a0'

分析:
由于class_getInstanceMethod方法回去父类里面寻找, 最后找到父类的方法,因为我们做了交换,所以父类的方法已经被交换son_work,而父类里面没有实现son_work

best_Swizzle

由于第二种方法在子类里面add了一个方法,所以交换正常。

swizzle一个不存的方法

我们将Fatherwork的具体实现去掉,然后使用上面俩个方法来测试swizzle

simple_Swizzle

报错

  'NSInvalidArgumentException', reason: '-[Son work]: unrecognized selector sent to instance 0x60c000006e40'

分析:
由于class_getInstanceMethod方法会找不到,返回nil。所以method_exchangeImplementations会失败,保持原样。所以最后仍然会找不到方法。

best_Swizzle

会循环调用son_work
分析:
由于class_getInstanceMethod方法会找不到,返回nil。这时add也不可能成功,最后交互也会失败,所以最后这种写法就变成了循环调用。

 - (void)son_work{
   NSLog(@"son_category work") ;
  [self son_work];
}

swizzle 不同class的俩个方法

如果我们把Fatherwork方法和animal方法交换,考虑下下面的代码。

- (void)animal_wrok{
    NSLog(@"animal work");
    // 这时如果访问self 的变量, 方法会怎么样?
}

相关文章

网友评论

    本文标题:iOS Method Swizzle的一些坑

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