簡體   English   中英

這兩種機制之間的混淆有什么區別

[英]What is the difference when swizzling between these 2 mechanisms

這兩種方式之間存在細微的差異。 我只是想澄清一下它們之間是否存在根本上的不同或錯誤

假設我們在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

實際上,這是一個很好的問題。 如果您使用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實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM