2017-02-20 49 views
0

这两种搅拌方式之间存在细微的差异。我只是想澄清,如果有什么根本不同或它们之间在这两种机制之间搅拌有什么区别

假设我们是在UIView

第一种方式混写viewDidLoad(使用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 
+0

您的代码工作?您为选择器swizzled_viewDidLoad调用class_getInstanceMethod,但该函数是Class Method,而不是实例方法。 –

回答

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

因为removeFromSuperviewUIView继承的,但在不UIWebView实现。