很早就看過(guò)一些關(guān)于 Method Swizzling 的博客,看完后一直沒(méi)有一個(gè)恰當(dāng)?shù)氖褂脠?chǎng)景能操練一下。最近寫(xiě)一個(gè) Demo 的時(shí)候發(fā)現(xiàn)要在很多控制器里寫(xiě)導(dǎo)航欄的返回按鈕,本來(lái)是復(fù)制一下或者繼承一下就行的。但是復(fù)制這種做法挺蠢的,繼承會(huì)讓代碼耦合性增加。這個(gè)時(shí)候我就突然的想到了 Method Swizzling,然后做了一個(gè)嘗試。
創(chuàng)建一個(gè) UIViewController 的分類(lèi),引入#import <objc/runtime.h>頭文件。基本代碼如下:
@implementation UIViewController (BackButton)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(swizzled_viewWillAppear:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
#pragma mark - Method Swizzling
- (void)swizzled_viewWillAppear:(BOOL)animated {
[self swizzled_viewWillAppear:animated];
//在這里判斷哪個(gè)控制器不需要返回按鈕
if (![self isMemberOfClass:NSClassFromString(@"ViewController")]) {
UIImage *image = [UIImage imageNamed:@"goBack_blue.png"];
UIButton *leftButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
[leftButton setImage:image forState:UIControlStateNormal];
[leftButton addTarget:self action:@selector(goBack) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:leftButton];
self.navigationItem.leftBarButtonItem = leftBarButtonItem;
}
NSLog(@"swizzled_viewWillAppear");
}
- (void)goBack {
[self.navigationController popViewControllerAnimated:YES];
}
@end
這樣就實(shí)現(xiàn)了,下篇見(jiàn)~