您好,登錄后才能下訂單哦!
如果你還不知道什么是Method Swizzling,你可以看看NSHipster 的文章 ,我簡(jiǎn)單介紹一下,method swizzling 可以看成劫持了一個(gè)方法。
我們可以看看NSHipster 的文章中有以下代碼:
- (void)xxx_viewWillAppear:(BOOL)animated {
[self xxx_viewWillAppear:animated];
NSLog(@"viewWillAppear: %@", self);
}
是不是覺(jué)得遞歸無(wú)限循環(huán),事實(shí)上并不會(huì),你可以這么理解,一個(gè)具體的SEL是個(gè)名字,一個(gè)具體的IMP是個(gè)函數(shù)指針,在類(lèi)里面它們是靠一個(gè)表建立聯(lián)系。
假設(shè)(純屬虛構(gòu)) UIViewController 的 @selector(viewWillAppear:) 對(duì)應(yīng)的內(nèi)部實(shí)現(xiàn)為以下
void _UIKIT_Internal_UIViewController_viewWillAppear(id vc, SEL selector, BOOL animated) {
...// ^_^蘋(píng)果私有代碼
}
假設(shè)UIViewController 的 @selector(xxx_viewWillAppear:) 的實(shí)現(xiàn)為以下
void my_xxx_viewWillAppear(id vc, SEL selector, BOOL animated) {
[vc performSelector:@selector(xxx_viewWillAppear) withObject:@(animated)];
NSLog(@"viewWillAppear: %@", vc);
}
那么未替換方法前@selector(viewWillAppear:)對(duì)應(yīng)的指針就是&_UIKIT_Internal_UIViewController_viewWillAppear
那么未替換方法前@selector(xxx_viewWillAppear:)對(duì)應(yīng)的指針就是&my_xxx_viewWillAppear
一旦替換方法后,@selector(viewWillAppear:)對(duì)應(yīng)的指針就是&my_xxx_viewWillAppear,
@selector(xxx_viewWillAppear:)對(duì)應(yīng)的指針就是&_UIKIT_Internal_UIViewController_viewWillAppear
my_xxx_viewWillAppear 中的 [vc performSelector:@selector(xxx_viewWillAppear) withObject:@(animated)];
相當(dāng)于什么,相當(dāng)于 調(diào)用@selector(xxx_viewWillAppear:)所指的函數(shù)&_UIKIT_Internal_UIViewController_viewWillAppear, 也就是相當(dāng)于調(diào)用原來(lái)的函數(shù),所以這并不是遞歸。
@implementation UIViewController (Tracking)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self replaceOriginalSelector:@selector(viewWillAppear:) withNewSelector:@selector(xxx_viewWillAppear:)];
});
}
- (void)xxx_viewWillAppear:(BOOL)animated {
[self xxx_viewWillAppear:animated];
NSLog(@"x_viewWillAppear: %@", self);
}
@end
@interface ViewController ()
@end
@implementation ViewController
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self replaceOriginalSelector:@selector(viewWillAppear:) withNewSelector:@selector(yyy_viewWillAppear:)];
});
}
- (void)yyy_viewWillAppear:(BOOL)animated {
[self yyy_viewWillAppear:animated];
NSLog(@"y_viewWillAppear: %@", self);
}
@end
3.也是順序問(wèn)題
以下,來(lái)自另一篇文章defagos.github.io
它是這么說(shuō)的,NSObject 實(shí)現(xiàn)了 -awakeFromNib,但是它的子類(lèi)UIView,孫類(lèi)UILabel都沒(méi)有在本類(lèi)實(shí)現(xiàn)- awakeFromNib,那么替換時(shí)如果不寫(xiě)在category +(void) load方法里,那么順序也是個(gè)問(wèn)題
假設(shè)我們先替換了UILabel的- awakeFromNib方法,然后再替換了UIView的- awakeFromNib,那么UILabel的- awakeFromNib方法就不會(huì)執(zhí)行UIView的- awakeFromNib方法,因?yàn)樗鼈兌际仟?dú)立替換的是NSObject方法,這篇文章defagos.github.io 提供了一個(gè)解決方案,當(dāng)本類(lèi)沒(méi)有實(shí)現(xiàn)方法(如 UILabel -awakeFromNib)時(shí),首先先添加一個(gè)block方法 調(diào)用[super awakeFromNib];,我初次看到也是覺(jué)得這個(gè)方式很好,但是我發(fā)現(xiàn)兩點(diǎn)不足,
在構(gòu)建objc_super時(shí),如果父類(lèi)本身沒(méi)有實(shí)現(xiàn)方法,.super_class = class_getSuperclass(clazz),這么寫(xiě)好像是沒(méi)有用的,似乎super_class要填真正實(shí)現(xiàn)方法的祖先類(lèi),而不能一概的寫(xiě)class_getSuperclass
struct objc_super super = {
.receiver = self,
.super_class = class_getSuperclass(clazz)
};
id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper;
由于 va_list 變量最后是靠宏 va_arg(ap, type)
來(lái)獲取的,type又是未知的,這個(gè)函數(shù)指針的強(qiáng)制轉(zhuǎn)換轉(zhuǎn)換可能會(huì)出現(xiàn)問(wèn)題
可見(jiàn),Swizzling正確的順序是十分重要的,(共同點(diǎn):類(lèi)本身沒(méi)有真正實(shí)現(xiàn)方法)
- (void)awakeFromNib {
[super awakeFromNib];
}
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。