iOS如何彻底避免数组越界
我们先来看看有可能会出现的数组越界Crash的地方;
1
2
3
4
5
6
7
|
- ( void )tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { WelfareItem *item = [_datasourceArray objectAtIndex:indexPath.row]; //有可能会越界,你在下拉刷新时会用[_datasourceArray removeAllObjects],这时你又点了某个cell就会Crash } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { WelfareItem *item = _datasourceArray[indexPath.row]; //有可能会越界,两个地方用了[tableView reloadData];后一个有[_datasourceArray removeAllObjects];前一个还没有执行完,就会Crash } |
上面代码是有可能会越界的;出现Crash也不好复现,发出去的App总是能收到几条Crash;解决这个问题也很简单代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
- ( void )tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { WelfareItem *item = nil; if (indexPath.row < [_datasourceArray count]) { //无论你武功有多高,有时也会忘记加 item = [_datasourceArray objectAtIndex:indexPath.row]; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { WelfareItem *item = nil; if (indexPath.row < [_datasourceArray count]) { item = [_datasourceArray objectAtIndex:indexPath.row]; } } |
问题又来了,无论你武功有多高,有时也会忘记加;所以我们要想一招制敌办法;我是想到了用Runtime把objectAtIndex方法替换一下;代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
/*! @category @abstract NSObject的Category */ @interface NSObject (Util) /*! @method swizzleMethod:withMethod:error: @abstract 对实例方法进行替换 @param oldSelector 想要替换的方法 @param newSelector 实际替换为的方法 @param error 替换过程中出现的错误,如果没有错误为nil */ + (BOOL)swizzleMethod:(SEL)originalSelector withMethod:(SEL)swizzledSelector error:(NSError **)error; @end # import "NSObject+Util.h" # import <objc runtime.h= "" > @implementation NSObject (Util) + (BOOL)swizzleMethod:(SEL)originalSelector withMethod:(SEL)swizzledSelector error:(NSError **)error { Method originalMethod = class_getInstanceMethod(self, originalSelector); if (!originalMethod) { NSString *string = [NSString stringWithFormat:@ " %@ 类没有找到 %@ 方法" ,NSStringFromClass([self class ]),NSStringFromSelector(originalSelector)]; *error = [NSError errorWithDomain:@ "NSCocoaErrorDomain" code:- 1 userInfo:[NSDictionary dictionaryWithObject:string forKey:NSLocalizedDescriptionKey]]; return NO; } Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector); if (!swizzledMethod) { NSString *string = [NSString stringWithFormat:@ " %@ 类没有找到 %@ 方法" ,NSStringFromClass([self class ]),NSStringFromSelector(swizzledSelector)]; *error = [NSError errorWithDomain:@ "NSCocoaErrorDomain" code:- 1 userInfo:[NSDictionary dictionaryWithObject:string forKey:NSLocalizedDescriptionKey]]; return NO; } if (class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) { class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } return YES; } @end @implementation NSArray (ErrerManager) + ( void )load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @autoreleasepool { [objc_getClass( "__NSArrayI" ) swizzleMethod: @selector (objectAtIndex:) withMethod: @selector (swizzleObjectAtIndex:) error:nil]; [objc_getClass( "__NSArrayM" ) swizzleMethod: @selector (objectAtIndex:) withMethod: @selector (swizzleObjectAtIndex:) error:nil]; }; }); } - (id)swizzleObjectAtIndex:(NSUInteger)index { if (index < self.count) { return [self swizzleObjectAtIndex:index]; } NSLog(@ "%@ 越界" ,self); return nil; //越界返回为nil } @end </objc> |
有了上面代码我们用 [_datasourceArray objectAtIndex:indexPath.row] 就不会发生越界Crash了;越界
了会返回nil;看来是一个比较不错的解决方案;把app发出去吧,结果我们Crash比之前高了好几倍(越界的Crash没有了,出新的Crash了);Crash如下
1
2
3
4
5
6
7
8
9
10
11
12
13
|
1 tbreader 0x002b93e9 tbreader + 2098153 2 libsystem_platform.dylib 0x33a66873 _sigtramp + 34 3 libsystem_blocks.dylib 0x33941ae1 _Block_release + 216 4 libobjc.A.dylib 0x333c11a9 + 404 5 CoreFoundation 0x25ba23a9 _CFAutoreleasePoolPop + 16 6 UIKit 0x2912317f + 42 7 CoreFoundation 0x25c565cd + 20 8 CoreFoundation 0x25c53c8b + 278 9 CoreFoundation 0x25c54093 + 914 10 CoreFoundation 0x25ba2621 CFRunLoopRunSpecific + 476 11 CoreFoundation 0x25ba2433 CFRunLoopRunInMode + 106 12 GraphicsServices 0x2cf0a0a9 GSEventRunModal + 136 13 UIKit 0x2918c809 UIApplicationMain + 1440 |
都是这个Crash,出现在iOS7以上(含iOS7),关键还没有用户反馈有问题,Crash高了几倍没有一个用户反馈这种情况还是少见的,大家测试还复现不了;测试了一周终于复现了一样的Crash;是这样出现的,替换了objectAtIndex方法有输入的地方出来了软键盘按手机Home键就Crash了;此法不行只,只能另寻他策了。后来我们就给数组新增扩展方法代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
@interface NSArray (SHYUtil) /*! @method objectAtIndexCheck: @abstract 检查是否越界和NSNull如果是返回nil @result 返回对象 */ - (id)objectAtIndexCheck:(NSUInteger)index; @end # import "NSArray+SHYUtil.h" @implementation NSArray (SHYUtil) - (id)objectAtIndexCheck:(NSUInteger)index { if (index >= [self count]) { return nil; } id value = [self objectAtIndex:index]; if (value == [NSNull null ]) { return nil; } return value; } @end |
把之前的代码 WelfareItem *item = [_datasourceArray objectAtIndex:indexPath.row] 改为 WelfareItem *item = [_datasourceArray objectAtIndexCheck:indexPath.row] 就可以了。这样就可以彻底解决数组越界 -[__NSArrayI objectAtIndex:]: index 100 beyond bounds [0 .. 1]' 错误了
最新文章
- Repeater控件 ---表格展示数据
- Android消息推送——JPush极光推送
- jquery.ajaxfileupload.js
- Linux-内存管理机制、内存监控、buffer/cache异同
- 2015-10-15 晴 APUE GIT
- 14的路 MySQL的btree索引和hash索引的区别
- quartz Cron表达式一分钟教程
- hdu 4773 Problem of Apollonius
- scale相关设置—颜色设置
- sql关键字过滤C#方法
- sso单点登录系统(解决session共享)
- Sum of Consecutive Prime Numbers POJ - 2739 线性欧拉筛(线性欧拉筛证明)
- php5.4使用dblib扩展,连接sqlserver中文乱码问题
- C++ primer 11章关联容器
- 实用ExtJS教程100例-006:ExtJS中Window的用法示例
- CentOS Grub、BASH 故障、解决方法
- 201621123012 《Java程序设计》第14次学习总结
- 当一个SQL语句同时出现了where,group by,having,order by的时候,执行顺序和编写顺序
- 编写高质量代码改善C#程序的157个建议——建议59:不要在不恰当的场合下引发异常
- SharedPreferences使用(通过键值保存数据)
热门文章
- Linux文件管理
- MongoDB查询转对象是出错Element '_id' does not match any field or property of class
- SQL Server中行列转换 Pivot UnPivot
- [LeetCode] Maximal Square 最大正方形
- [LeetCode] Add and Search Word - Data structure design 添加和查找单词-数据结构设计
- [LeetCode] Valid Palindrome 验证回文字符串
- [LeetCode] Sqrt(x) 求平方根
- Netty学习笔记之一(Netty解析简单的Http Post Json 请求)
- Ubuntu上基于开源代码PhoneMe的J2ME环境搭建及使用
- navicat注册码