zoukankan      html  css  js  c++  java
  • 构建自己的NSZombie

    当开启 xcode zombie 选项,发送消息到一个被  "释放了的对象"  时

        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";

    打印结果:

    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 可以得出以下信息:

    1,我们向一个 "已经释放了的对象" ObjZomies 发送了 setName: 方法。

    2,在oz 被release 前后  object_getClassName(oz) 打印的结果不同,即oz 的isa 指向的class 变啦 0.0

    ObjZomies 和 _NSZombie_ObjZomies  

    3,有没有注意到 那三个%p  都是一样的  0x7fcb71f047c0, 说明oz 这货release 后并没有别释放。

    所以 "已经释放了的对象"  并没有释放  而是变成了 "僵尸",在程序运行期间一直在内存驻留。 当然在启用xcode zombie 选项后,所有类都不能 "幸免"  变成  "僵尸" 

     _NSZombie_ObjZomies  当然是运行时添加进去的类,像KVO 一样,根据目标类假如是A  那么运行时就会生成一个特殊功能的类 xxx_A  来行使某些功能。

    _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.html
    http://www.cocoachina.com/ios/20141204/10526.html

  • 相关阅读:
    两种存储思路
    越来越浅
    我了解的前端史
    关于称赞小孩
    怎么写递归
    Python笔记(十八):协程asyncio
    网络协议笔记(一):HTTP协议基础知识
    Linux笔记(三):常用命令
    算法笔记(九):二分查找
    数据结构笔记(二):栈、队列
  • 原文地址:https://www.cnblogs.com/DamonTang/p/4915093.html
Copyright © 2011-2022 走看看