0

这两种调酒方式略有不同。我只想澄清他们之间是否存在根本不同或错误

假设我们正在viewDidLoad调动UIView

第一种方式(使用class_addMethod):

@implementation UIView (SwizzleFirstWay)

+ (void)load  {
    SEL originalSelector = @selector(viewDidLoad);
    SEL swizzledSelector = @selector(swizzled_viewDidLoad);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
    class_addMethod(self,
                    originalSelector,
                    class_getMethodImplementation(self, originalSelector),
                    method_getTypeEncoding(originalMethod));

    // Adding the method
    class_addMethod(self,
                    swizzledSelector,
                    class_getMethodImplementation(self, swizzledSelector),
                    method_getTypeEncoding(swizzledMethod));
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

+ (void)swizzled_viewDidLoad {
    // ... the swizzled implementation
    // ...
    // ...
    [self swizzled_viewDidLoad]; // calling back to the original implementation
}

@end

第二种方式(不使用class_addMethod):

+ (void)load  {
    SEL originalSelector = @selector(viewDidLoad);
    SEL swizzledSelector = @selector(swizzled_viewDidLoad);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
    // NOT USING class_addMethod
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

+ (void)swizzled_viewDidLoad {
    // ... the swizzled implementation
    // ...
    // ...
    [self swizzled_viewDidLoad]; // calling back to the original implementation
}

@end
4

1 回答 1

0

非常好的问题,实际上。如果你在method_exchangeImplementations没有class_addMethod先调用的情况下使用,你可能会意外地调整你的超类实现。这样做的原因是class_getInstanceMethod在方法未在类本身中实现的情况下搜索超类以查找继承的实现。显然,这不是您想要实现的目标。

一个简单的例子。使用以下代码

@interface UIWebView (SwizzlingTest)

- (void)swizzled_removeFromSuperview {
    [self swizzled_removeFromSuperview];
}

+ (void)load {
    SEL originalSelector = @selector(removeFromSuperview);
    SEL swizzledSelector = @selector(swizzled_removeFromSuperview);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

@end

结果是

-[UICheckeredPatternView swizzled_removeFromSuperview]:无法识别的选择器发送到实例 0x101b24250

因为removeFromSuperview继承自UIView,但未在 中实现UIWebView

于 2017-02-21T18:24:52.917 回答