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]‘ 错误了

时间: 2024-08-14 23:50:30

iOS如何彻底避免数组越界的相关文章

iOS 数组越界 Crash处理经验

我们先来看看有可能会出现的数组越界Crash的地方: - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { WelfareItem *item = [_datasourceArray objectAtIndex:indexPath.row];//有可能会越界,你在下拉刷新时会用[_datasourceArray removeAllObjects],这时你又点了某个

iOS 关于数组越界的解决方法

所谓的数组越界,就是假如你的下标总数现在为32个,然后你在下一秒又执行了一个方法要从50个数据里惊醒赋值啊 筛选之类的 而你此时数量为32 50的数据还没有请求到 往往会出现数组越界的崩溃信息 大概是这样的 -[__NSArrayI objectAtIndex:]: index 100 beyond bounds [0 .. 9]'  具体的解决方式我们通常会选择把数组做个判断列如 return nil; 虽然在大多数情况下是可以的,但是多少并不严谨,如果你设置了一个事件循环执行的NStimer

iOS数组越界

数组越界就是假如你的下标总数现在为32个,然后你在下一秒又执行了一个方法要从50个数据里进行赋值啊筛选之类的,而你此时数组里的值为32个,50的数据还没有请求到,往往会出现数组越界的崩溃信息,大概是这样的 -[__NSArrayI objectAtIndex:]: index 100 beyond bounds [0 .. 9]' 具体的解决方式我们通常会选择吧数组做个判断入return nil; 虽然在大多数情况下是可以的,但是多少并不严谨,如果你设置了一个事件循环执行的nstimer而你的数

QRCode 数组越界异常

因为需求的缘故需要解析出ios二维码的地址,把解析的地址传到按钮上 把功能写好之后用几张二维码测试没问题后提交到svn上,第二天生产环境正好发版,发现有个应用的按钮点了一直没反应,看了下控制台发现报错 居然是数组越界...纠结了好久.最后点到那个二维码看看有什么特别之处 一切尽在无言中(我擦...居然是1000多像素的二维码,你逗我呢)...

谨防数组越界!

今天第一次对数组越界问题有了深切的感受,数组越界如果在Release版本中运行也不会报错,如果是Debug版本的话,若直接通过常量数值引用数组下标会被检测到数组越界,若通过变量引用数组下标也是不会被检测到的!!! 测试下面的代码, 1 #include <stdio.h> 2 3 int main(void) 4 { 5 int arr[1][1] = {20}, brr[1] = {1}, y = 5; 6 7 //printf("%d\n", arr[5][0] ==

数组越界

1. 找出下列代码的错误 void test() { char string[10]; char *str="0123456789"; strcpy(string,str); }字符串str需要11个字节才能存放下(包括末尾的'\0'),而string只有10个字节的空间:strcpy会导致数组越界. void test() { char string[10]; char str[10]; int i; for(int i=0; i<10; i++) { str[i]='a';

数组越界保护与消息传递black机制

数组越界保护if(index.row <= [array count]) 发送消息[[NSNotificationCenter defaultCenter]     postNotificationName:@"chuandi" object:self]; 接收消息 自己写个action的动作[[NSNotificationCenter defaultCenter] addObserver:self                                         

ListView 适配器实现getviewtypcount() 数组越界IndexOutOfBoundException

ListView中Item的多布局显示,需要用到了getViewTypecount和getItemViewType这两个重写方法,但是做完后出现了如下提示错误:java.lang.ArrayIndexOutOfBoundsException: (数组越界) 原因:居然是getItemViewType这里里面返回的Type必须是从0开始的,如果getviewtypecount等于2,那么getItemViewType返回的数值是从0~1的常数.简单说,在刚开始设置type常量时,是从0开始递增的,

从一道简单模拟题看数组越界以及其他

题目要求比较明确,可能做起来难度不是很大. 但我这道题用了比较久的时间. 原因是我用了一种特别容易错的方法.我在移动数组元素的时候采用不用辅助数组由前往后复制的方法(想来我也真是没事找事干),然后在这种方法下我起初交了许多遍WA,然后自己经过长时间的测试终于发现了问题所在,不止一个,各种逻辑错误. 总结主要有以下几点: 分类讨论不够明确,不够完整 没有考虑到前边操作对后边数据的影响 没有意识到数组越界的后果(a[-1],a[maxn]) 要发现和解决这些问题并不容易,需要有很高的调试技巧,通过这