国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > iOS > 正文

iOS中實現(xiàn)檢測Zoombie對象的具體方法

2020-07-26 02:33:08
字體:
來源:轉載
供稿:網(wǎng)友

前言

我們大家都知道,如果在XCode中開啟了Zoombie Objects。如圖。

那么在一個對象釋放后,再次給該對象發(fā)送消息,在Xcode控制臺中,可看到如下打印信息。這些信息可以幫助我們定位問題。

ZoombieDemo[12275:2841478] *** -[Test test]: message sent to deallocated instance 0x60800000b000

那么究竟XCode是如何實現(xiàn)僵尸對象的檢查的,我們將來一一揭曉。

實現(xiàn)原理

在《Effective Objective-C 》一書中有提到過僵尸指針的實現(xiàn)方式。

通過hook NSObject的dealloc的方法,在一個對象要釋放的時候,通過objcduplicateClass復制NSZombie類,生成NSZombieOriginaClass,并且將當前對象的isa指向新生成的類。這塊內(nèi)存不會釋放。

因為在給該對象發(fā)消息時,NSZombieOriginaClass并未實現(xiàn)原有類的方法,所以會走完整的消息轉發(fā)。所以我們能取出具體的OriginaClass(去掉NS_Zombie),當前sel,打印出來。

[class seletor]:message sent to deallocated instance 0x22909"

簡單來說,就是將對象指向一個新的類,因為新類里面并沒有原有類方法的實現(xiàn),所以必定會走到消息轉發(fā)中。

以上說的是動態(tài)生成新的類,類名是通過固定前綴拼接而成,將isa指向該類。其實還有一種方式,就是指向固定的類,原有類名通過關聯(lián)對象的方式來存儲。

既然知道了原理,可以動手實現(xiàn)一下。

動手實現(xiàn)

首先是hook dealloc方法。在NSObject+HookDealloc中實現(xiàn)。

+ (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{  Class class = [self class];  SEL originalSelector = NSSelectorFromString(@"dealloc");  SEL swizzledSelector = @selector(swizzledDealloc);  Method originalMethod = class_getInstanceMethod(class, originalSelector);  Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);    BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));  if (success) {   class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));  } else {   method_exchangeImplementations(originalMethod, swizzledMethod);  } });}

動態(tài)生成新的類

在swizzledDealloc中,我們通過"Zoombie_"拼接原始類名,得到一個新的類名。然后生成該類,添加 forwardingTargetForSelector的實現(xiàn)。便于在消息轉發(fā)的時候得到調用信息。

NSString *Zoombie_Class_Prefix = @"Zoombie_";// 指向動態(tài)生成的類,用Zoombie拼接原有類名NSString *className = NSStringFromClass([self class]);NSString *zombieClassName = [Zoombie_Class_Prefix stringByAppendingString: className]; Class zombieClass = NSClassFromString(zombieClassName);if(zombieClass) return; zombieClass = objc_allocateClassPair([NSObject class], [zombieClassName UTF8String], 0); objc_registerClassPair(zombieClass);class_addMethod([zombieClass class], @selector(forwardingTargetForSelector:), (IMP)forwardingTargetForSelector, "@@:@");object_setClass(self, zombieClass);

forwardingTargetForSelector的方法實現(xiàn),原始類名,去掉前綴即可得到。因為這里已經(jīng)是調用到已釋放對象的方法,我們直接abort掉,程序將崩潰。

id forwardingTargetForSelector(id self, SEL _cmd, SEL aSelector) { NSString *className = NSStringFromClass([self class]); NSString *realClass = [className stringByReplacingOccurrencesOfString:Zoombie_Class_Prefix withString:@""]; NSLog(@"[%@ %@] message sent to deallocated instance %@", realClass, NSStringFromSelector(aSelector), self); abort();}

指向固定類

指向已有的ZoombieObject類,類名存在關聯(lián)對象中。

 // 指向固定的類,原有類名存儲在關聯(lián)對象中NSString *originClassName = NSStringFromClass([self class]);objc_setAssociatedObject(self, "OrigClassNameKey", originClassName, OBJC_ASSOCIATION_COPY_NONATOMIC);object_setClass(self, [ZoombieObject class]);

同上,在ZoombieObject中實現(xiàn)forwardingTargetForSelector方法,可以得到調用信息。原始類名通過關聯(lián)對象獲取。

- (id)forwardingTargetForSelector:(SEL)aSelector { NSLog(@"[%@ %@] message sent to deallocated instance %@", objc_getAssociatedObject(self, "OrigClassNameKey"), NSStringFromSelector(aSelector), self); abort();}

forwardingTargetForSelector是消息轉發(fā)的第二步,我們也可以不在這里處理,等到最后一步forwardInvocation,不過要生成方法簽名,要略微復雜些。

要想走到forwardInvocation,methodSignatureForSelector返回不能是空。這里我們返回了StubProxy類中stub的方法簽名(已經(jīng)定義好的類和方法),最后就回走到forwardInvocation,通過invocation.selector可得到當前調用方法名。通過關聯(lián)對象獲取到原始類名。

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *sig = [super methodSignatureForSelector:aSelector]; if (!sig) {  sig = [StubProxy instanceMethodSignatureForSelector:@selector(stub)]; }  return sig;}- (void)forwardInvocation:(NSInvocation *)anInvocation { NSLog(@"[%@ %@] message sent to deallocated instance %@", objc_getAssociatedObject(self, "OrigClassNameKey"), NSStringFromSelector(anInvocation.selector), self);}

這樣,一個簡單的檢測僵尸指針的方案就實現(xiàn)了。

demo在此。

兩種方式都實現(xiàn)了,可通過調整NSObject+HookDealloc中,swizzledSelector的值來切換。my_dealloc是指向動態(tài)類,swizzledDealloc是指向固定類。

SEL swizzledSelector = @selector(my_dealloc);

在App運行起來后,點擊button,即可觸發(fā)。

總結

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網(wǎng)的支持。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 上犹县| 西昌市| 额敏县| 洛南县| 荔波县| 商河县| 乌兰察布市| 潞西市| 临海市| 竹山县| 湘潭县| 虹口区| 濮阳县| 句容市| 顺义区| 准格尔旗| 玉环县| 华池县| 天等县| 诸暨市| 澜沧| 江陵县| 西充县| 竹北市| 弋阳县| 连州市| 台山市| 日土县| 榆社县| 二连浩特市| 钟祥市| 阳城县| 承德县| 三江| 德格县| 普兰店市| 陆良县| 南宫市| 无锡市| 澄迈县| 安福县|