我们先来看看有可能会出现的数组越界Crash的地方。

- (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;解决问题也非常easy代码例如以下:

- (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方法替换一下。代码例如以下:

/*!
@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

有了上面代码我们用 [_datasourceArray
objectAtIndex:indexPath.row] 就不会发生越界Crash了。越界

了会返回nil。看来是一个比較不错的解决方式。把app发出去吧,结果我们Crash比之前高了好几倍(越界的Crash没有了,出新的Crash了)。Crash例如以下

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了;此法不行仅仅,仅仅能另寻他策了。

后来我们就给数组新增扩展方法代码例如以下

@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 数组越界 Crash加工经验的更多相关文章

  1. iOS数组越界

    数组越界就是假如你的下标总数现在为32个,然后你在下一秒又执行了一个方法要从50个数据里进行赋值啊筛选之类的,而你此时数组里的值为32个,50的数据还没有请求到,往往会出现数组越界的崩溃信息,大概是这 ...

  2. 第17月第7天 iOS 数组越界,防Crash处理

    1. 上面方法已经可以避免crash,为了避免冗余的代码,写一个NSArray的分类,利用runtime替换NSArray的对象方法objectAtIndex:,在这里进行判断,捕获异常: #impo ...

  3. iOS如何彻底避免数组越界

    我们先来看看有可能会出现的数组越界Crash的地方: ? 1 2 3 4 5 6 7 - (void)tableView:(UITableView *)tableView didSelectRowAt ...

  4. iOS开发——高级篇——iOS如何彻底避免数组越界

    我们先来看看有可能会出现的数组越界Crash的地方: ? 1 2 3 4 5 6 7 - (void)tableView:(UITableView *)tableView didSelectRowAt ...

  5. iOS应用的crash日志的分析基础

        Outline如何获得crash日志如何解析crash日志如何分析crash日志     1. iOS策略相关     2. 常见错误标识     3. 代码bug 一.如何获得crash日志 ...

  6. iOS 数组字典操作

    iOS开发中需要大量对dictionary和array进行操作,因此我们需要一种更加安全可靠的操作方法来避免不必要的crash.当然可以通过自定义dictionary 和array重载增删改查的方法来 ...

  7. iOS开发之Crash分析,以及收集

    一  先谈谈iOS的Crash收集方式: 1. APP 发生crash,用户手机手机上肯定会有crash纪录,当然删除了该app,或是删了再装 crash纪录还是没了. 2. 如果用户设置-隐私  同 ...

  8. 墨菲定律与 IndexOutOfBoundsException(数组越界异常)

    今天维护又反馈了一问题过来,查询试卷时报数组越界异常: 2017-02-28 10:45:24,827[ERROR] HttpException[10.32.111.7:60446:2D07867BE ...

  9. Objective-c防止数组越界而崩溃(全局效果)

    数组越界其实是很基本的问题,但是解决起来除了count的判断,还有每个调用的时候都要去判断一遍 对于不明确的数据总会有崩溃的风险 然而 每次调用都判断 那是太累了 so ..runtime&c ...

随机推荐

  1. 近期刷题的c语言总结。

    首先是三个数学函数... /* 函数名: floor 功 能: 下舍入,返回小于或者等于指定表达式的最大整数 说明:返回x的下限,如74.12的下限为74,-74.12的下限为-75.返回值为floa ...

  2. 【HDOJ】1263 水果

    hash,使用stl map ac.学了find_if等强大的东西,第一次使用stl模板. #include <iostream> #include <cstdio> #inc ...

  3. 应付配置文件 Profile

    (N) System Administrator > Profile > System Profile Option Name Site Application Responsibilit ...

  4. poj2079

    根据凸包的单峰性质,穷举第一个顶点然后先更新第三个顶点,再更新第二个顶点 ..] of longint; ans,n,t,k,i,j:longint; function cross(i,j,k:lon ...

  5. BZOJ_1180_[CROATIAN2009]_OTOCI_(LCT)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1180 三种操作: 1.询问x,y是否连通,如果不连通,建一条边x,y 2.把x节点的权值改为t ...

  6. 虚拟主机 (Virtual Host)

    虚拟主机 (Virtual Host) 是在同一台机器搭建属于不同域名或者基于不同 IP 的多个网站服务的技术. 可以为运行在同一物理机器上的各个网站指配不同的 IP 和端口, 也可让多个网站拥有不同 ...

  7. Java开发心得

    1. Spring概述 Spring 是一个开源框架,是为了解决企业应用程序开发复杂性由Rod Johnson创建的.框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J ...

  8. C#调用C++编写的DLL函数, 以及各种类型的参数传递 z

    1. 如果函数只有传入参数,比如: C/C++ Code Copy Code To Clipboard //C++中的输出函数 int__declspec(dllexport) test(consti ...

  9. 数据结构:二级指针与Stack的数组实现

    [简介] Stack,栈结构,即传统的LIFO,后进先出,常用的实现方法有数组法和链表法两种.如果看过我上一篇文章<数据结构:二级指针与不含表头的单链表>,一定会看到其中的关键在于,利用v ...

  10. LightOJ 1074 Extended Traffic SPFA 消负环

    分析:一看就是求最短路,然后用dij,果断错了一发,发现是3次方,有可能会出现负环 然后用spfa判负环,然后标记负环所有可达的点,被标记的点答案都是“?” #include<cstdio> ...