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 + 20981532 libsystem_platform.dylib 0x33a66873 _sigtramp + 343 libsystem_blocks.dylib 0x33941ae1 _Block_release + 2164 libobjc.A.dylib 0x333c11a9 + 4045 CoreFoundation 0x25ba23a9 _CFAutoreleasePoolPop + 166 UIKit 0x2912317f + 427 CoreFoundation 0x25c565cd + 208 CoreFoundation 0x25c53c8b + 2789 CoreFoundation 0x25c54093 + 91410 CoreFoundation 0x25ba2621 CFRunLoopRunSpecific + 47611 CoreFoundation 0x25ba2433 CFRunLoopRunInMode + 10612 GraphicsServices 0x2cf0a0a9 GSEventRunModal + 13613 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]' 错误了
iOS如何彻底避免数组越界的更多相关文章
- iOS开发——高级篇——iOS如何彻底避免数组越界
我们先来看看有可能会出现的数组越界Crash的地方: ? 1 2 3 4 5 6 7 - (void)tableView:(UITableView *)tableView didSelectRowAt ...
- iOS 数组越界 Crash加工经验
我们先来看看有可能会出现的数组越界Crash的地方. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSInd ...
- iOS数组越界
数组越界就是假如你的下标总数现在为32个,然后你在下一秒又执行了一个方法要从50个数据里进行赋值啊筛选之类的,而你此时数组里的值为32个,50的数据还没有请求到,往往会出现数组越界的崩溃信息,大概是这 ...
- Objective-c防止数组越界而崩溃(全局效果)
数组越界其实是很基本的问题,但是解决起来除了count的判断,还有每个调用的时候都要去判断一遍 对于不明确的数据总会有崩溃的风险 然而 每次调用都判断 那是太累了 so ..runtime&c ...
- 数组越界保护与消息传递black机制
数组越界保护if(index.row <= [array count]) 发送消息[[NSNotificationCenter defaultCenter] postNotificati ...
- 解决Android时时更新listview数组越界问题
时时更新数据一般出现在金融.股票行业对数据的准确性要求极高情况下使用. 先来看看下面一段代码, public class MainActivity extends Activity { private ...
- Android 【问题汇总】列表数组越界的问题
遇到了一个诡异的问题,ListView发生数组越界(偶尔会),程序崩溃. 错误信息如下: W/dalvikvm( ): threadid=: thread exiting with uncaught ...
- Java中的数组越界问题
Java中数组初始化和OC其实是一样的,分为动态初始化和静态初始化, 动态初始化:指定长度,由系统给出初始化值 静态初始化:给出初始化值,由系统给出长度 在我们使用数组时最容易出现的就是数组越界问题, ...
- java.sql.SQLException之数组越界
java.sql.SQLException之数组越界 1.具体错误如下: (1)java.sql.SQLException:Parameter index out of range(0<1) ( ...
随机推荐
- JavaScript第一节课
1.用法:位于<script></script>可以位于body和head中,不限制标签数量,也可以创建外部Js文件,然后引入.(引入方法:<script src=&qu ...
- mybatis常见易出错
在学习mybatis的过程中,发现了很多错误,这里记录一下,以供后来使用 1,config.xml文件中配置项的顺序: org.apache.ibatis.exceptions.Persistence ...
- [LeetCode] Product of Array Except Self 除本身之外的数组之积
Given an array of n integers where n > 1, nums, return an array output such that output[i] is equ ...
- [LeetCode] Wildcard Matching 外卡匹配
Implement wildcard pattern matching with support for '?' and '*'. '?' Matches any single character. ...
- [转载]Web前端开发工程师编程能力飞升之路
[背景] 如果你是刚进入web前端研发领域,想试试这潭水有多深,看这篇文章吧:如果你是做了两三年web产品前端研发,迷茫找不着提高之路,看这篇文章吧:如果你是四五年的前端开发高手,没有难题能难得住你的 ...
- JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(四):自定义T4模板快速生成页面
前言:上篇介绍了下ko增删改查的封装,确实节省了大量的js代码.博主是一个喜欢偷懒的人,总觉得这些基础的增删改查效果能不能通过一个什么工具直接生成页面效果,啥代码都不用写了,那该多爽.于是研究了下T4 ...
- git初级--配置
source: http://www.cnblogs.com/sakurayeah/p/5800424.html 一.注册github账号 github网址https://github.com/ 下一 ...
- express不是内部或外部命令
网上找了一下原因,是因为express在4.0以后把命令工具单独分出来了,所以安装完express后,还得再安装express-generator: 如果不是采用的全局安装,则需要把 "安装 ...
- 使用ARP欺骗, 截取局域网中任意一台机器的网页请求,破解用户名密码等信息
ARP欺骗的作用 当你在网吧玩,发现有人玩LOL大吵大闹, 用ARP欺骗把他踢下线吧 当你在咖啡厅看上某一个看书的妹纸,又不好意思开口要微信号, 用arp欺骗,不知不觉获取到她的微信号和聊天记录,吓一 ...
- 【Codeforces 738B】Spotlights
Theater stage is a rectangular field of size n × m. The director gave you the stage's plan which act ...