iOS 两种方法交换的区别

下面两种实现是在iOS开发中最常用的方法交换方式,那么两种实现方式具体有什么区别呢?
首先,以上两种实现都可以达到方法交换的效果,但是方案一在某些情况下会发生崩溃,而方案二相对安全一些。

方案一:
+ (void)swizzleInstanceMethod:(SEL)originalSel with:(SEL)swizzledSel {

    Method originalMethod = class_getInstanceMethod(self, originalSel);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSel);

    method_exchangeImplementations(originalMethod, swizzledMethod);

}
方案二:
+ (void)swizzleInstanceMethod:(SEL)originalSel with:(SEL)swizzledSel {

    Method originalMethod = class_getInstanceMethod(self, originalSel);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSel);
    
    BOOL didAddMethod =
    class_addMethod(self,
                    originalSel,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));
    
    if (didAddMethod) {
        class_replaceMethod(self,
                            swizzledSel,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
  1. 假设有两个A、B两个类,B是A的子类,
@interface A : NSObject

@end

@implementation A

- (void)test {
    NSLog(@"test");
}

@end

@interface B : A

@end

@implementation B

- (void)btest {
    [self btest];
    NSLog(@"btest");
}

@end
  1. 然后交换B类的方法
    [self swizzleInstanceMethod:@selector(test) with:@selector(btest)];

交换前:


image.png

使用第一种方案交换后:

image.png

此时A类的实例调用test方法,就会发生崩溃。
因为test方法属于A类,B类未实现test方法,交换方法导致直接改变了A类方法列表中的结构
当A类调用test方法时,其实调用了btest方法,而btest内部[self btest];此时等价于[A btest]; btest方法属于B类,所以会发生unrecognized selector错误

使用第二种方案交换后:

image.png

利用class_addMethod特性,只判断当前类方法,不判断继承方法为子类重新添加了test方法,此时方法交换只会影响B类,不会发生崩溃

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容