2017-02-20 67 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實現。