zoukankan      html  css  js  c++  java
  • runtime MethodSwizzle 实践之 奇怪crash : [UIKeyboardLayoutStar release]: message sent to deallocated instance

    情景: 使用MethodSwizzle 实现对数组、字典 等系统方法的安全校验。显然能达到预期效果,但实际发现当

    键盘显示的情况下  home app 进入后台,再单击app  图标 切换回前台时 发生crash :

     [UIKeyboardLayoutStar release]: message sent to deallocated instance

    UIKeyboardLayoutStar 是键盘上的布局的视图吧,

    整个工程都在ARC下 构建,很奇怪,而且必须。

    信息:

    http://huang.sh/2015/02/%E4%B8%80%E4%B8%AA%E5%A5%87%E6%80%AA%E7%9A%84crash-uikeyboardlayoutstar-release/

    http://code4app.com/ios/DurexKit%E5%AE%89%E5%85%A8%E5%B7%A5%E5%85%B7%E5%8C%85/5325b421933bf0463d8b49ec

    其中都有提到DurexKit  原理都是一样的,上面提到原因是替换了 NSArray的objectAtIndex: 方法,

    不过在我的项目原因是替换了NSMutableArray 的objectAtIndex:( NSMutableArray和 NSArray 的objectAtIndex:都有替换,单独替换 NSArray 的objectAtIndex:方法则不会引起crash) 

     

    解决方案:给 添加非ARC 支持,并改写实现

    有提到:。。貌似 arc 有时也不一定可靠。

     

    ----------------------2015.3.23-----更新--0.0--继续填坑啊----------------------------------

    话说使用 语法糖初始化 数组和 字典 真的好方便。。。@{....}  @[...]  但是很容易埋雷。。大多数里面存的都是变量 在代码里。so , 也需要校验 。

    最初使用 MethodSwizzle 很嗨皮啊,首先涉及可变参数在替换的方法里 试图使用NSInvocation 来解决 传递多个参数的问题,最后 莫名crash 。。你可以试试。

    再说说数组和字典里的类簇(工厂模式):

    http://blog.sunnyxx.com/2014/12/18/class-cluster/ 

    后来发现如果你用语法糖 初始化数组 crash 信息如下:

    '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from xx

     解决方案使用静态方法 + objc_msgSend 来实现:

    #import <objc/message.h>
    
    #define CurrentClass objc_getClass("__NSArrayI")
    
    static id array_safe_initWithObjects(id self, SEL _cmd, const id* objects,unsigned int count){
        id orignialResult = nil;
        @try {
            orignialResult = objc_msgSend(self, @selector(array_safe_initWithObjects:count:),objects,count);
        }
        @catch (NSException *exception) {
            DDLogDebug(@"=__NSPlaceholderArray===BUSTED!");
        }
        return orignialResult ;
    }
    
    @implementation NSArray (SafeCheck)
    
    +(void)load{
        //添加
        [CurrentClass swizzleInstanceSelector:@selector(objectAtIndex:) withNewSelector:@selector(safeObjectsAtIndex:)];
        
        [objc_getClass("__NSPlaceholderArray")   swizzleSelector: @selector(initWithObjects:count:) withNewSelector:@selector(array_safe_initWithObjects:count:) andNewIMP:(IMP)&array_safe_initWithObjects];
    }

     

    + (void) swizzleSelector:(SEL)originalSelector
             withNewSelector:(SEL)newSelector
                   andNewIMP:(IMP)imp{
        
        Method originMethod = class_getInstanceMethod(self, originalSelector);
        const char * methodEncodeType = method_getTypeEncoding(originMethod);
        BOOL methodAdded = class_addMethod(self, newSelector, imp, methodEncodeType);
        
        if (methodAdded) {
            Method newMethod = class_getInstanceMethod(self,newSelector);
            method_exchangeImplementations(newMethod, originMethod);
        }else{
            DDLogDebug(@"=====faile=");
        }
    }

    在运行时中会维护 selector 和 IMP 对应关系表。

    同理字典也一样呢可以使用这种方法 添加语法糖校验。

    #import <objc/message.h>
    
    static id dic_safe_initWithObjects(id self, SEL _cmd, const id* objects, const id* keys, unsigned int count) {
        
        id orignialResult = nil;
        
        @try {
            orignialResult = objc_msgSend(self, @selector(dic_safe_initWithObjects:forKeys:count:), objects, keys, count);
        }
        @catch (NSException *exception) {
            DDLogDebug(@"__NSPlaceholderDictionary===BUSTED!");
        }
        
        return orignialResult;
    }
    
    @implementation NSDictionary (SafeCheck)
    +(void)load{
          [objc_getClass("__NSPlaceholderDictionary") swizzleSelector:@selector(initWithObjects:forKeys:count:) withNewSelector:@selector(dic_safe_initWithObjects:forKeys:count:) andNewIMP:(IMP)&dic_safe_initWithObjects];
    }

     

     

  • 相关阅读:
    js查找字符串中重复的子字符串
    未知盒子宽高使盒子垂直水平居中
    标准盒模型和怪异盒模型的差异
    Vue练习(跑马灯效果)
    node后端中MVC与前端中的MVVM之间的区别
    ES6中对Promise解析
    ES6中对箭头函数的使用
    ES6对map解析
    ES6中对Set解析
    ES6解构赋值全了解
  • 原文地址:https://www.cnblogs.com/DamonTang/p/4342366.html
Copyright © 2011-2022 走看看