Runtime編程 - Swizzle Stuff

objective-c的instance method調用實際上是查表再通過C形式調用的過程,這個函數表是可以操作的,這樣就給了我們可以在運行時修改的機會,這種做法叫swizzle .

<objc/runtime.h>裏面提供了API,我們以調換NSString的lowercaseString與我們的category裏面的stoneLowercaseString爲目標。實現swizzle基本上會用到category,先看category裏面的代碼:

.h文件
===================================
#import <Foundation/Foundation.h>

@interface NSString (Stone)
- (
NSString *)stoneLowercaseString;
@end

.m文件
===================================
#import "NSString+Stone.h"

@implementation NSString (Stone)
- (
NSString *)stoneLowercaseString{
   
// 遞歸調用?不是,實際上在運行到這裏之前我們已經做了swap,所以這裏
   
// 調用的是原版的lowercaseString,達到了調用原方法的目的。
   
NSString *lowercase = [self stoneLowercaseString];
   
NSLog(@"[Stone] %@", lowercase);
   
return lowercase;
}
@end


方法的swap以及測試,swizzle的調用時機越早越好,一般會寫在app的didLaunch事件中。
===================================
    // swizzle stuff
   
// 這裏注意不要寫成了class_getClassMethod
   
Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));
   
Method stoneMethod = class_getInstanceMethod([NSString class], @selector(stoneLowercaseString));
   
method_exchangeImplementations(originalMethod, stoneMethod);
   
   
// test
   
NSString *test = @"Gundam Exia";
    NSLog(@"lower = %@", [test lowercaseString]);


輸出
===================================
2015-09-08 09:59:08.621 SwizzleDemo[16503:811706] [Stone] gundam exia
2015-09-08 09:59:08.622 SwizzleDemo[16503:811706] lower = gundam exia


*注意點
不要爲了用swizzle而用swizzle,此技巧一旦出現問題的話會非常難以調試和debug。因此,除非是常規辦法沒法實現或者實現起來很麻煩的需求,一般避免用swizzle。最常見的用法是用於調試沒有源碼的類實現等等。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章