在这两种机制之间徘徊时有什么区别

时间:2017-02-20 12:56:41

标签: ios objective-c objective-c-runtime method-swizzling

这两种混合方式之间存在细微差别。我只想澄清它们之间是否有根本不同或错误

假设我们在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

1 个答案:

答案 0 :(得分:0)

非常好的问题,实际上。如果您先使用t = [(3,300),(1,100),(2,200),(4,400),(5,500)] t.sort() print(t) t = t[0:3] print(t) 而不先调用method_exchangeImplementations,则可能会意外地调动您的超类实现。原因是class_addMethod在类本身没有实现方法的情况下搜索超类的继承实现。显然,这不是你想要实现的目标。

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

class_getInstanceMethod

结果

  

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

因为@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 继承自removeFromSuperview,但未在UIView中实施。