iOS-Runtime之数组越界

作者: FlyElephant | 来源:发表于2016-08-15 16:53 被阅读2517次

关于数组越界目前大概有两种方式,一种是通过分类添加安全的索引方法,第二种就是Runtime实现,第一种如果是个人开发比较建议,如果是团队开发很难得到保证和推动,关于Runtime处理数组越界网上有人说是在iOS7及以上有软键盘输入的地方按Home键退出,会出现崩溃,测试过两台手机iOS8.1和iOS9.3暂时没有出现问题,如果之后出现问题会更新文章.

方法交换

Runtime解决数据越界及字典key或value为nil的情况,主要通过Runtime的方法交换实现,可以扩展一下NSObject分类:
<pre><code>`
@implementation NSObject (FlyElephant)

  • (void)swizzleMethod:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector{
    Class class = [self class];

    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    BOOL didAddMethod = class_addMethod(class,
    originalSelector,
    method_getImplementation(swizzledMethod),
    method_getTypeEncoding(swizzledMethod));

    if (didAddMethod) {
    class_replaceMethod(class,
    swizzledSelector,
    method_getImplementation(originalMethod),
    method_getTypeEncoding(originalMethod));
    } else {
    method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    }

@end</code></pre> 现在需要扩展NSArray和NSDictionary分类,实现方法交换: <pre><code>
@implementation NSArray (FlyElephant)

  • (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    @autoreleasepool {
    [objc_getClass("__NSArray0") swizzleMethod:@selector(objectAtIndex:) swizzledSelector:@selector(emptyObjectIndex:)];
    [objc_getClass("__NSArrayI") swizzleMethod:@selector(objectAtIndex:) swizzledSelector:@selector(arrObjectIndex:)];
    [objc_getClass("__NSArrayM") swizzleMethod:@selector(objectAtIndex:) swizzledSelector:@selector(mutableObjectIndex:)];
    [objc_getClass("__NSArrayM") swizzleMethod:@selector(insertObject:atIndex:) swizzledSelector:@selector(mutableInsertObject:atIndex:)];
    }
    });
    }
  • (id)emptyObjectIndex:(NSInteger)index{
    return nil;
    }

  • (id)arrObjectIndex:(NSInteger)index{
    if (index >= self.count || index < 0) {
    return nil;
    }
    return [self arrObjectIndex:index];
    }

  • (id)mutableObjectIndex:(NSInteger)index{
    if (index >= self.count || index < 0) {
    return nil;
    }
    return [self mutableObjectIndex:index];
    }

  • (void)mutableInsertObject:(id)object atIndex:(NSUInteger)index{
    if (object) {
    [self mutableInsertObject:object atIndex:index];
    }
    }

@end

@implementation NSDictionary (FlyElephant)

  • (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    @autoreleasepool {
    [objc_getClass("__NSDictionaryM") swizzleMethod:@selector(setObject:forKey:) swizzledSelector:@selector(mutableSetObject:forKey:)];
    }
    });
    }
  • (void)mutableSetObject:(id)obj forKey:(NSString *)key{
    if (obj && key) {
    [self mutableSetObject:obj forKey:key];
    }
    }
    @end`</code></pre>

注意__NSArray0表示一般空数组,__NSArrayI表示一般数组,__NSArrayM可变数组,NSArray和NSMutableArray相当于工厂,最终实现通过上面三个类进行实现的,有兴趣的可以自行了解一下类簇.

测试

测试代码:
<pre><code>`
NSArray *emptyArr = [NSArray new];
NSLog(@"%@",[emptyArr objectAtIndex:10]);

NSArray *arr = @[@"FlyElephant",@"keso"];
NSString *result = [arr objectAtIndex:10];
NSLog(@"%@",result);

NSMutableArray *mutableArr = [[NSMutableArray alloc] initWithArray:arr];
NSLog(@"%@", mutableArr[100]);
NSString *obj;
[mutableArr addObject:obj];

//NSDictionary
NSString *dictValue;
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
[mutableDict setValue:dictValue forKey:@"FlyElephant"];
[mutableDict setObject:dictValue forKey:dictValue];
NSLog(@"%@",mutableDict);`</code></pre>

2016.08.17更新
昨天测试的时候还没有问题,今天早上运行项目发现一个莫名其妙的问题:
<pre><code>**[UIKeyboardLayoutStar release]: message sent to deallocated instance 0x1459e0600**</code></pre>
通过Runtime进行对数组字典进行方法交换之后,之前对键盘输入的场景没有完全弄清楚,完整过程应该是,文本框输入文字→Home键进入后台→点击App图标重新进入→崩溃,有的时候前两步就直接崩溃了,因此Runtime的这个文件需要通过mrc管理:
一般项目都是 ARC 模式,需要单独问Runtime的这个问题添加MRC支持,
Build Phases -> Compile Sources找到文件设置 -fno-objc-arc 标签。

如果项目是MRC 模式,则为 ARC 模式的代码文件加入 -fobjc-arc 标签.

同时可以为相应的代码块添加autoreleasepool:
<pre><code>@autoreleasepool { if (index >= self.count || index < 0) { return nil; } return [self arrObjectIndex:index]; }</code></pre>

相关文章

  • iOS-Runtime之数组越界

    关于数组越界目前大概有两种方式,一种是通过分类添加安全的索引方法,第二种就是Runtime实现,第一种如果是个人开...

  • iOS-Runtime之数组越界

    关于数组越界目前大概有两种方式,一种是通过分类添加安全的索引方法,第二种就是Runtime实现,第一种如果是个人开...

  • iOS Crash三部曲~之二常见Crash

    1 越界 1.1 数组越界 第1类崩溃就是越界问题,最常见的就是数组越界。 崩溃信息: 分析: 可以看出当前数组的...

  • iOS--再也不用担心数组越界

    iOS--再也不用担心数组越界 iOS--再也不用担心数组越界

  • java.lang.ArrayIndexOutOfBoundsE

    名字上看是数组下标越界错误,解决方法就是查看为什么下标越界。 如下: 12代表越界数组的下标, originalD...

  • C数组知识点(越界风险、数组传递、栈溢出)

    一、一维数组 1.数组初始化 2.数组越界会导致的风险 数组越界就是访问数组元素的时候,索引超过了定义的数组长度,...

  • 数组越界

    刚才遇到了个数组越界错误,下拉刷新几十次才会出现一次carsh,于是进行断点定位,却发现断点后便不会再carsh。...

  • iOS 数组越界的处理和优化方案。

    iOS开发中最常见的列表数据,必须使用数组,但是使用数组总会出现数组越界的情况,下面列出三种优化数组越界的方式。 ...

  • 窥探Swift之数组安全索引与数组切片

    本文摘自窥探Swift之数组安全索引与数组切片 前言:通常我们对数组进行索引操作会考虑是否越界,通常的处理方法是对...

  • swift扩展类-Array

    在使用数组的时候,最常见的异常就是数组越界了,为了避免在开发的时候出现越界的情况,写了几个扩展的方法,用于缓减越界...

网友评论

  • 刘超_a594:NSMutableArray *mutableArr = [[NSMutableArray alloc] initWithArray:arr];
    NSLog(@"%@", mutableArr[100]); 用括号取值直接蹦
    IOSMan:取数组下标时应该替换objectAtIndexedSubscript:方法
  • 金鑫_123:还有bug,如果数组里面放一个元素如arr[@"111"], arr[10]还会奔溃
    Tank丶Farmer:@Rocherster 完美解决
    Roct:只有一个元素的不可变数组是__NSSingleObjectArrayI 需要再写一个交换方法
  • Nglszs:我用了你arrObjectIndex这个方法,在此方法前打印nslog却发现执行多次,这个是因为系统原因还是其他原因
    金鑫_123:同样求解
  • nenhall:很好,正好我也遇到此原因导致的崩溃

本文标题:iOS-Runtime之数组越界

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