亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

iOS中如何實現檢測Zoombie對象功能

發布時間:2021-06-28 13:49:15 來源:億速云 閱讀:131 作者:小新 欄目:移動開發

這篇文章將為大家詳細講解有關iOS中如何實現檢測Zoombie對象功能,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

前言

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

iOS中如何實現檢測Zoombie對象功能

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

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

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

實現原理

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

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

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

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

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

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

既然知道了原理,可以動手實現一下。

動手實現

首先是hook dealloc方法。在NSObject+HookDealloc中實現。

+ (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);
  }
 });
}

動態生成新的類

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

NSString *Zoombie_Class_Prefix = @"Zoombie_";
// 指向動態生成的類,用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的方法實現,原始類名,去掉前綴即可得到。因為這里已經是調用到已釋放對象的方法,我們直接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類,類名存在關聯對象中。

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

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

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

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

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

- (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);
}

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

demo在此。

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

SEL swizzledSelector = @selector(my_dealloc);

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

關于“iOS中如何實現檢測Zoombie對象功能”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

ios
AI

宁海县| 海伦市| 庆阳市| 庆云县| 汝阳县| 万安县| 双城市| 杭锦旗| 达孜县| 津市市| 乌海市| 五华县| 安康市| 镇平县| 雷波县| 专栏| 大余县| 西充县| 交城县| 鹤壁市| 开阳县| 镇原县| 西昌市| 衡东县| 福贡县| 建始县| 平邑县| 德惠市| 长治县| 昌平区| 乐都县| 林芝县| 淮阳县| 兴隆县| 华坪县| 武陟县| 镇沅| 信宜市| 山东| 广安市| 文水县|