zoukankan      html  css  js  c++  java
  • iOS之利用runtime,避免可变数组和可变字典为nil或者数组越界导致的崩溃

    NSArray、NSMutableArray、NSDictionary、NSMutableDictionary、是我们的在iOS开发中非常常用的类。当然,在享受这些类的便利的同时,它们也给我们带来一些困扰。粗心我们可能会调用addObject:传入一个nil, 也有可能是会objectAtIndex:传入一个越界的index。尤其是在数据基本依赖于服务端返回的的情况,这种crash大幅增加。最近项目上经常出现NSDictionary的setObject:forKey:的nil object的崩溃。我们希望为这种崩溃找一个解决办法。

    解决方案

    函数包装

    我们希望能够用一个统一的方法解决粗心的程序员可能传入的nil object。我们最先想到的想法是对这些函数进行一个包装,比如objectAtIndex,我们写一个如下的函数

    - (id)safeObjectAtIndex:(NSUInteger)index {   
        if (index >= self.count) {
            return nil;
        }
        return [self objectAtIndex:index];
    }

    以后所有调用objectAtIndex的地方统统替换为safeObjectAtIndex。 不过,这显然不是我想要的,我不希望改变现有的调用方式,大家可能是通过[]或objectAtIndex(不推荐)的方式获取数组元素,如果要做替换的话改动势必非常大,而且不便于以后的移植。我们希望代码调用objectAtIndex的时候,能够被我们先捕获到,进行处理之后再调用Cocoa的这个方法。Objective-C作为一门动态语言,有强大的动态加载的能力,提供了Method swizzling实现这样的功能。现在,黑魔法起飞。

    Method swizzling

    关于Method swizzling的具体实现,不打算多说,这里谈一下我遇到的问题。最初在做Method swizzling的时候,我尝试去替换NSArrat的objectAtIndex:,但我始终没有办法替换掉这个方法。后来,搞了半天才发现,我们使用的NSAarray或者NSMutableArray并不是我们所看到样子,它们是class cluster。objectAtIndex:并不是他们的方法,而是他们背后的concrete class: __NSArrayI __NSArrayM的方法。解决了这个问题,剩下的就很简单了。

    使用

    直接把XTSafeCollection.hXTSafeCollection.m拖入工程,NSArrayNSMutableArrayNSDictionaryNSMutableDictionary这些类的API以前是怎么调用的,还怎么写,完全不用修改。Demo里,我全部以传统的会引起crash的方式调用代码,以下是我的Demo的代码和输出

    NSArray *array = @[@"a", @"b"];
    NSMutableArray *mutableArray = [@[@"aa", @"bb"] mutableCopy];
         
    // Object at index
    NSLog(@"%@", array[10]);
    NSLog(@"%@", mutableArray[100]);
         
    // add object
    [mutableArray addObject:nil];
         
    // Insert object
    [mutableArray insertObject:nil atIndex:0];
    [mutableArray insertObject:@"cc" atIndex:10];
         
    // Replace object
    [mutableArray replaceObjectAtIndex:0 withObject:nil];
    [mutableArray replaceObjectAtIndex:10 withObject:@"cc"];
         
    // Dictionary
    NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
    mutableDictionary[nil] = @"1";
    mutableDictionary[@"1"] = nil;
    2015-08-25 18:10:23.932 XTSafeCollection[29067:443479] [__NSArrayI objectAtIndex:] index {10} beyond bounds [0...1]
    2015-08-25 18:10:23.933 XTSafeCollection[29067:443479] (null)
    2015-08-25 18:10:23.933 XTSafeCollection[29067:443479] [__NSArrayM objectAtIndex:] index {100} beyond bounds [0...1]
    2015-08-25 18:10:23.933 XTSafeCollection[29067:443479] (null)
    2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM addObject:], NIL object.
    2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM insertObject:atIndex:] NIL object.
    2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM insertObject:atIndex:] index {10} beyond bounds [0...1].
    2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM replaceObjectAtIndex:withObject:] NIL object.
    2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM replaceObjectAtIndex:withObject:] index {10} beyond bounds [0...1].
    2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSDictionaryM setObject:forKey:] NIL key.

    安装

    源码: https://github.com/wuwen1030/XTSafeCollection

    已知问题

    替换NSMuatbelArray的objectAtIndex:引起键盘展示状态态切换后台的崩溃,抛出*** -[UIKeyboardLayoutStar release]: message sent to deallocated instance 0x7f883beac9c0 在这里找到了解决方法

  • 相关阅读:
    Delphi Help
    RAD 10 新控件 TSearchBox TSplitView
    滚动条
    c++builder Active Form
    chart左侧
    RAD 10 蓝牙
    浏览器插件 火狐插件
    c++builder delphi 调用dll dll编写
    模拟键盘 键盘虚拟代码
    oracle怎么把一个用户下的表复制给另一个用户?(授予表权限)
  • 原文地址:https://www.cnblogs.com/rglmuselily/p/7473548.html
Copyright © 2011-2022 走看看