美文网首页iOS实战iOS之runtimeiOS开发
method Swizzling实践--alloc hooker

method Swizzling实践--alloc hooker

作者: 树下老男孩 | 来源:发表于2015-08-06 23:39 被阅读1724次

    废话不多说,直接进入正题。这次碰到的问题主要是在项目里涉及到的一些内存问题,先说说这个项目的整体结构,由于要实现跨平台的缘故,所以在最顶层是由lua来编写相关的业务代码的,实现安卓和iOS端业务的快速开发,中间是一层统一的c++接口,然后iOS跟安卓根据这份统一的c++接口实现各自平台的底层逻辑代码,比如对于一个View,c++的统一接口为:

    void *createView(const char *type)
    

    然后创建view由iOS跟安卓各自去实现,iOS端可以实现c++跟oc的混合编码,可以直接调用oc的代码,然后lua调用c++借由swig实现互调,这个有很多种方法可以自己去挑选合适的。
      下面说说框架中遇到的问题,由于这中间涉及到lua,c++跟oc的混合编码,而且oc使用的是mrc方式(项目开始的时间比较早),因此内存管理的问题变得尤为重要。正常的处理逻辑是:创建时,lua调用c++去new一个oc对象;释放时,lua调用c++的析构函数,然后在析构函数里完成oc对象的释放。然后怎么确保这些对象按照这个逻辑被释放掉了呢~
      对于这个问题,我采取的策略是在每个对象创建的时候做一个记录,然后在对象被清理的时候从记录中删除,最后看看记录中还有没有多余的对象,以此来判断对象是否都被释放完毕(或者有啥新的思路也可以提出来哈~),实现这个需要借助两个东西:method SwizzlingNSHashTable,method Swizzling可以参考之前的博客,NSHashTable主要利用它可以持有weak类型的成员变量,NSHashTableWeakMemory表示添加到该hash table时并不会增加对象的引用技术,当添加的对象在外部被释放时,该table会自动删除相应的对象。

    NSHashTable *hashTable = [NSHashTable hashTableWithOptions: NSHashTableWeakMemory]; 
    

    因此可以看出具体的实现方式了:利用method Swizzling去hook nsobject的init方法,并将其添加到NSHashTableWeakMemory型的NSHashTable,最后看看该table中还有哪些对象,证明这些对象还没有被释放掉,可以通过这来检测整个对象的创建跟释放逻辑是否正确。
      下面给出示例代码,比如要记录UIView对象创建跟释放:

    static NSHashTable *hashTable;//存储创建的对象
    @implementation UIView (AllocHook)
    
    //method Swizzling的方法,我们hook该方法,并额外将该对象添加到NSHashTable中
    -(instancetype)customInit
    {
        if (!hashTable) {
            hashTable = [NSHashTable hashTableWithOptions:NSHashTableWeakMemory];
        }
        [hashTable addObject:self];
        return [self customInit];
    }
    @end
    
    //一个hook对象,用于开启method Swizzling
    @implementation ViewAllocHooker
    
    -(void)startRecord
    {
        Class class = [UIView class];
        
        SEL originalSelector = @selector(init);
        SEL swizzledSelector = @selector(customInit);
        
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        //交换原来的init方法跟新的customInit方法
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    
    

    这样每个调用init方法创建的UIView或其子类都将被记录到NSHashTable中,同时由于该table只是持有添加对象的弱引用,因此可以在后面查看该table还有哪些对象就可以确定这些对象还没被释放,以验证该框架是否正确。详细的例子代码可以查看github,其中的ViewAllocHooker可以采用单例,由于是示例代码就不更改了,有啥改进的地方欢迎提出~~

    相关文章

      网友评论

        本文标题:method Swizzling实践--alloc hooker

        本文链接:https://www.haomeiwen.com/subject/uzkbqttx.html