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

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

我們知道,如果在XCode中開啟了Zoombie Objects。如圖伙菜。

1.png

那么在一個對象釋放后,再次給該對象發(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的方法娇哆,在一個對象要釋放的時候,通過objc_duplicateClass復(fù)制_NS_Zombie類勃救,生成_NS_Zombie_OriginaClass碍讨,并且將當(dāng)前對象的isa指向新生成的類。這塊內(nèi)存不會釋放蒙秒。

因為在給該對象發(fā)消息時勃黍,_NS_Zombie_OriginaClass并未實現(xiàn)原有類的方法,所以會走完整的消息轉(zhuǎn)發(fā)晕讲。所以我們能取出具體的OriginaClass(去掉_NS_Zombie)覆获,當(dāng)前sel榜田,打印出來。

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

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

以上說的是動態(tài)生成新的類,類名是通過固定前綴拼接而成蛔六,將isa指向該類荆永。其實還有一種方式,就是指向固定的類国章,原有類名通過關(guān)聯(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)欧瘪。便于在消息轉(zhuǎn)發(fā)的時候得到調(diào)用信息。

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)是調(diào)用到已釋放對象的方法芥被,我們直接abort掉,程序?qū)⒈罎ⅰ?/p>

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類脾猛,類名存在關(guān)聯(lián)對象中撕彤。

 // 指向固定的類,原有類名存儲在關(guā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方法羹铅,可以得到調(diào)用信息。原始類名通過關(guān)聯(lián)對象獲取愉昆。

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

    abort();
}

forwardingTargetForSelector是消息轉(zhuǎn)發(fā)的第二步职员,我們也可以不在這里處理,等到最后一步forwardInvocation跛溉,不過要生成方法簽名焊切,要略微復(fù)雜些扮授。

要想走到forwardInvocation,methodSignatureForSelector返回不能是空专肪。這里我們返回了StubProxy類中stub的方法簽名(已經(jīng)定義好的類和方法)刹勃,最后就回走到forwardInvocation,通過invocation.selector可得到當(dāng)前調(diào)用方法名嚎尤。通過關(guān)聯(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)了,可通過調(diào)整NSObject+HookDealloc中关贵,swizzledSelector的值來切換遇骑。my_dealloc是指向動態(tài)類,swizzledDealloc是指向固定類揖曾。

SEL swizzledSelector = @selector(my_dealloc);

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末模暗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子念祭,更是在濱河造成了極大的恐慌兑宇,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粱坤,死亡現(xiàn)場離奇詭異隶糕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)站玄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門枚驻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人株旷,你說我怎么就攤上這事再登。” “怎么了晾剖?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵锉矢,是天一觀的道長。 經(jīng)常有香客問我齿尽,道長沽损,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任循头,我火速辦了婚禮绵估,結(jié)果婚禮上炎疆,老公的妹妹穿的比我還像新娘。我一直安慰自己国裳,他們只是感情好形入,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缝左,像睡著了一般唯笙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盒使,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音七嫌,去河邊找鬼少办。 笑死,一個胖子當(dāng)著我的面吹牛诵原,可吹牛的內(nèi)容都是我干的英妓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绍赛,長吁一口氣:“原來是場噩夢啊……” “哼蔓纠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吗蚌,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤腿倚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蚯妇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敷燎,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年箩言,在試婚紗的時候發(fā)現(xiàn)自己被綠了硬贯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡陨收,死狀恐怖饭豹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情务漩,我是刑警寧澤拄衰,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站菲饼,受9級特大地震影響肾砂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宏悦,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一镐确、第九天 我趴在偏房一處隱蔽的房頂上張望包吝。 院中可真熱鬧,春花似錦源葫、人聲如沸诗越。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嚷狞。三九已至,卻和暖如春荣堰,著一層夾襖步出監(jiān)牢的瞬間床未,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工振坚, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留薇搁,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓渡八,卻偏偏與公主長得像啃洋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子屎鳍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉宏娄,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,719評論 0 9
  • 版權(quán)聲明本文轉(zhuǎn)自網(wǎng)易杭州前端技術(shù)部公眾號,由作者授權(quán)發(fā)布逮壁。 前言 大白(Baymax)孵坚,迪士尼動畫《超能陸戰(zhàn)隊》中...
    XueYongWei閱讀 2,033評論 2 11
  • p2p安全排行榜_華融道理財 華融道理財你的首選~ p2p安全排行榜_華融道理財 ECHO 處于關(guān)閉狀態(tài)。 余額寶...
    魚蒲醋17095閱讀 175評論 0 0
  • 十月份以來圍繞著一件事窥淆,內(nèi)心的波浪時時翻滾十饥,同樣的事以前不走心的樂此不疲的做下去,是因為覺得還有希望祖乳,一切只是暫時...
    有個內(nèi)在小人的我閱讀 158評論 0 0