構建本身的NSZombie

當開啓 xcode zombie 選項,發送消息到一個被  "釋放了的對象"  時html

    ObjZomies *oz = [[ObjZomies  alloc] init];
    oz.name = @"obz";
    
    NSLog(@"ObjZomies :----%@---%s---%p",[ObjZomies class],object_getClassName(oz),oz);
    [oz release];
    
    NSLog(@"ObjZomies :-------%@----%s----%p",[ObjZomies class],object_getClassName(oz),oz);
    
    oz.name = @"z----o";

打印結果:ios

2015-10-27 17:32:43.303 Zombies[68811:1009530] ObjZomies :----ObjZomies---ObjZomies---0x7fcb71f047c0
2015-10-27 17:32:43.304 Zombies[68811:1009530] ObjZomies :-------ObjZomies----_NSZombie_ObjZomies----0x7fcb71f047c0
2015-10-27 17:32:43.304 Zombies[68811:1009530] *** -[ObjZomies setName:]: message sent to deallocated instance 0x7fcb71f047c0

很神奇....   分析log 能夠得出如下信息:xcode

1,咱們向一個 "已經釋放了的對象" ObjZomies 發送了 setName: 方法。ui

2,在oz 被release 先後  object_getClassName(oz) 打印的結果不一樣,即oz 的isa 指向的class 變啦 0.0atom

ObjZomies 和 _NSZombie_ObjZomies  spa

3,有沒有注意到 那三個%p  都是同樣的  0x7fcb71f047c0, 說明oz 這貨release 後並無別釋放。指針

因此 "已經釋放了的對象"  並無釋放  而是變成了 "殭屍",在程序運行期間一直在內存駐留。 固然在啓用xcode zombie 選項後,全部類都不能 "倖免"  變成  "殭屍" code

 

 _NSZombie_ObjZomies  固然是運行時添加進去的類,像KVO 同樣,根據目標類假如是A  那麼運行時就會生成一個特殊功能的類 xxx_A  來行使某些功能。htm

_NSZombie_ 前綴 + ObjZomies  就構成了運行時建立的  用於捕捉 "殭屍" 的功能類。對象

 

 

_NSZombie_MyClass 也就是 捕捉殭屍類 ,

做用是   捕捉 給一個    "已經釋放的對象"   發消息時 可以觸發異常的機制,並提醒開發者具體是發到了哪一個已經被釋放的類,以及 哪一個消息。

這依賴於oc 強大的動態性,以及消息傳遞機制。

簡單歸納原理:

      當一個類A  的實例a 的引用計數爲0 時,調用delloc 進行內存清理工做,固然它的基類是NSobject  最終會調到 NSObject 的dealloc 中。這時候若是讓它走完的話,a 也就釋放啦。咱們也永遠不知道它是誰。

     因此不能讓a 釋放,讓a 成爲一個"殭屍" 也就是a 的內存永遠駐留在程序運行時,建立一個 捕捉殭屍的類 B,在消息發相a 時轉發到B 中拋出異常,並提示相關信息。 即 a--isa-->B  把a的isa指針指向B ,(這裏不理解的須要好好作作功課啦)那麼a 就會用isa 到B 中去找對應實現。

 

實現以下:

注意main.m 環境爲非ARC,並開啓xcode zombie 相關選項

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import <objc/runtime.h>
#import "ObjZomies.h"

void EmpthIMP(id obj,SEL _cmd){}


NSMethodSignature * ZombieMethodSignatureForSelector(id obj,SEL _cmd,SEL selector){
    Class class = object_getClass(obj);
    NSString *className = NSStringFromClass(class);
    className = [className substringFromIndex:[@"CMZombie_" length]];
    
    NSLog(@"Selector %@ sent to deallocated instance %p of class %@", NSStringFromSelector(selector), obj, className);
    abort();
  
    return nil;
}


Class ZombifyClass(Class class){
    
    NSString * className = NSStringFromClass(class);
    NSString *zombieClassName = [@"CMZombie_" stringByAppendingString:className];
    
    Class zombieClass = NSClassFromString(zombieClassName);
    if (zombieClass) {
        return zombieClass;
    }
    //構建本身的NSZombie
    zombieClass = objc_allocateClassPair(nil, [zombieClassName UTF8String], 0);
    class_addMethod(zombieClass, @selector(methodSignatureForSelector:), (IMP)ZombieMethodSignatureForSelector, "@@::");
//這裏很容易理解,+initialize 存在於MetaClass 中,實例方法則存在於Class 中。 class_addMethod(object_getClass(zombieClass), @selector(initialize), (IMP)EmpthIMP,
"v@:"); objc_registerClassPair(zombieClass); return zombieClass; } void ZombieDealloc(id obj,SEL _cmd){ Class c = ZombifyClass(object_getClass(obj));
// 把obj 的isa 指向 咱們自定義的 "捕捉殭屍類" _NSZombie_MyClass object_setClass(obj, c); }
void EnableZombies(void){ Method m = class_getInstanceMethod([NSObject class],@selector(dealloc)); method_setImplementation(m , (IMP)ZombieDealloc); }

int main(int argc, char * argv[]) { //啓用 EnableZombies(); ObjZomies *oz = [[ObjZomies alloc] init]; oz.name = @"obz"; NSLog(@"ObjZomies :----%@---%s---%p",[ObjZomies class],object_getClassName(oz),oz); [oz release]; NSLog(@"ObjZomies :-------%@----%s----%p",[ObjZomies class],object_getClassName(oz),oz); oz.name = @"z----o"; @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
#import <Foundation/Foundation.h>

@interface ObjZomies : NSObject
@property (nonatomic,copy) NSString *name;

@end

#import "ObjZomies.h"

@implementation ObjZomies
@end

 

再次運行:

2015-10-27 17:55:55.433 Zombies[68883:1030347] ObjZomies :----ObjZomies---ObjZomies---0x7f825ae00790
2015-10-27 17:55:55.435 Zombies[68883:1030347] ObjZomies :-------ObjZomies----CMZombie_ObjZomies----0x7f825ae00790
2015-10-27 17:55:55.435 Zombies[68883:1030347] Selector setName: sent to deallocated instance 0x7f825ae00790 of class ObjZomies

so cool 。

 

     

   參考:https://www.mikeash.com/pyblog/friday-qa-2014-11-07-lets-build-nszombie.htmlhttp://www.cocoachina.com/ios/20141204/10526.html

相關文章
相關標籤/搜索