Runtime消息轉發雖然功能強大,但需要我們了解并且能更改對應類的源代碼,因為我們需要實作自己的轉發邏輯。當我們無法觸碰到某個類的源代碼,卻想更改這個類某個方法的實作時,該怎麼辦呢?可能繼承類并重寫方法是一種想法,但是有時無法達到目的。這裡介紹的是 Method Swizzling ,它通過重新映射方法對應的實作來達到“偷天換日”的目的。跟消息轉發相比,Method Swizzling 的做法更為隐蔽,甚至有些冒險,也增大了debug的難度。下面我們來了解一下Method Swizzling 的具體應用。
使用Method Swizzling 一鍵修改字型
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL systemSel = @selector(willMoveToSuperview:);
SEL swizzlSel = @selector(swizzl_willMoveToSuperview:);
Method sysMethod = class_getInstanceMethod([self class], systemSel);
Method swizzlMethod = class_getInstanceMethod([self class], swizzlSel);
//将系統方法 的IMP轉換為自定義的方法的IMP,如果自定義的方法的IMP沒有實作,那麼就會傳回YES。
BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzlMethod), method_getTypeEncoding(swizzlMethod));
if (isAdd) {
class_replaceMethod(self, swizzlSel, method_getImplementation(sysMethod), method_getTypeEncoding(sysMethod));
}else{
method_exchangeImplementations(sysMethod, swizzlMethod);
}
});
}
- (void)swizzl_willMoveToSuperview:(UIView *)newSuperView{
//這一步也很關鍵,是必須要調用的,因為這一步回去執行系統的方法對應的iMP,因為切換了。多以我們可以通過這方式來擴充系統方法。
[self swizzl_willMoveToSuperview:newSuperView];
if ([self isKindOfClass:NSClassFromString(@"UIButtonLabel")]) {
self.backgroundColor = [UIColor redColor];
}
self.font = [UIFont fontWithName:SCRIPT_NAME size:self.font.pointSize];
}
使用同樣的原理,我們可以對系統的方法進行拓展。