IOS之方法混寫(swizzling.)

來源:互聯網
上載者:User

IOS之方法混寫(swizzling.)

OC中的混寫(swizzling)是指透明地把一個方法換成另外一個。簡明的說就是在運行時替換方法。利用方法混寫可以改變那些沒有原始碼的對象(包括系統對象)的行為。

方法混寫的代碼看起來相對比較直觀的,舉個例子說明一下,之前做本地化翻譯的時候就有用到 swizzling 方法。直接去swizze方法 awakeFromNib 然後替換成自己的方法實現以實現本地化翻譯。詳細可以看這篇文章:IOS本地化應用程式。

主要用到的代碼也就這兩句:

 

+(void)load  {      // Autoload : swizzle -awakeFromNib with -localizeNibObject as soon as the app (and thus this class) is loaded      Method localizeNibObject = class_getInstanceMethod([NSObject class], @selector(localizeNibObject));      Method awakeFromNib = class_getInstanceMethod([NSObject class], @selector(awakeFromNib));      method_exchangeImplementations(awakeFromNib, localizeNibObject);  } 
-(void)localizeNibObject  {        //本地化操作....    // Call the original awakeFromNib method      [self localizeNibObject]; // this actually calls the original awakeFromNib (and not localizeNibObject) because we did some method swizzling  } 

今天又跑回去github上看了一下AGi18n這個開源項目,作者將原來的代碼全部都換成了分類實現了,看起來更加的直觀,當同樣也還是通過 swizzling 實現。

 

如 NSobject + AGi18n 分類代碼:

 

#import NSObject+AGi18n.h#import @implementation NSObject (AGi18n)//By default do nothing when localizing- (void)localizeFromNib {}#pragma mark - Method swizzling+ (void)load {    Method awakeFromNibOriginal = class_getInstanceMethod(self, @selector(awakeFromNib));    Method awakeFromNibCustom = class_getInstanceMethod(self, @selector(awakeFromNibCustom));            //Swizzle methods    method_exchangeImplementations(awakeFromNibOriginal, awakeFromNibCustom);}- (void)awakeFromNibCustom {    //Call standard methods    [self awakeFromNibCustom];        //Localize    [self localizeFromNib];}@end

上面代碼 交換了 awakeFromNib 和 awakeFromNibCustom 方法的實現,在程式一啟動的時候就去執行。由於該類是 NSObject 的分類,而所有控制項都是繼承 NSObject 的,這樣,本地化操作只需在需要本地化的控制項分類裡重寫一下 localizeFromNib 這個方法即可,以UIButton為例,本地化操作就變得非常簡單了。

 

 

#import UIButton+AGi18n.h@implementation UIButton (AGi18n)- (void)localizeFromNib {    //Replace text with localizable version    NSArray *states = @[@(UIControlStateNormal), @(UIControlStateHighlighted), @(UIControlStateDisabled), @(UIControlStateSelected), @(UIControlStateApplication)];    for (NSNumber *state in states) {        NSString *title = [self titleForState:state.integerValue];        if (title.length > 0) {            [self setTitle:[[NSBundle mainBundle] localizedStringForKey:title value:@ table:nil] forState:state.integerValue];        }    }}@end

-----------------------------------------------------------------------------------------------------分割線-----------------------------------------------------------------------------------------------------------------------------

 

《IOS 7 Programming:Pushing the Limits》一書中對方法混寫舉了一個在NSNotificationCenter中添加觀察者時列印日誌的例子。通過上下兩個例子的對比,AGi18n在 swizzling 時還是欠缺部分考慮的。

 

@interface NSObject(RNSwizzle)+(IMP)swizzleSelector:(SEL)origSelector withIMP:(IMP)newIMP;@end@implementation NSObject(RNSwizzle)+(IMP)swizzleSelector:(SEL)origSelector withIMP:(IMP)newIMP{    Class class = [self class];    Method origMethod = class_getInstanceMethod(class, origSelector);    IMP origIMP = method_getImplementation(origMethod);    if (!class_addMethod(self, origSelector, newIMP, method_getTypeEncoding(origMethod))) {        method_setImplementation(origMethod, newIMP);    }        return origIMP;}@end
接下來看看細節。首先給這個方法傳遞一個選取器和一個函數指標(IMP)。我們要做的是把該方法的當前實現替換為新實現,並返回舊實現的指標以便以後調用。需要考慮3種情況:類可能直接實現了這個方法,方法可能是類階層中的某個父類實現的,或者方法根本沒有實現。如果該類或某個父類實現了這個方法,調用 class_getInstanceMethod 會返回一個 IMP,否則就返回 NULL。

 

如果方法根本沒有實現,或者是某個父類實現的,那就需要用 class_addMethod 添加方法,這跟通常的覆蓋方法是一樣的。如果 class_addMethod 失敗了,我們就知道了是此類直接實現了正在混寫的方法,那麼就轉而用 method_setImplementation 來把舊實現替換為 新實現。

好了之後,返回原來的 IMP,調用者怎麼用傳回值是它自己的事。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.