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

  1. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  2. WelfareItem *item = [_datasourceArray objectAtIndex:indexPath.row];//有可能会越界,你在下拉刷新时会用[_datasourceArray removeAllObjects],这时你又点了某个cell就会Crash
  3. }
  4.  
  5. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  6. WelfareItem *item = _datasourceArray[indexPath.row];//有可能会越界,两个地方用了[tableView reloadData]。后一个有[_datasourceArray removeAllObjects]。前一个还没有运行完,就会Crash
  7. }

上面代码是有可能会越界的;出现Crash也不好复现。发出去的App总是能收到几条Crash;解决问题也非常easy代码例如以下:

  1. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  2. WelfareItem *item = nil;
  3. if (indexPath.row < [_datasourceArray count]) {//不管你武功有多高,有时也会忘记加
  4. item = [_datasourceArray objectAtIndex:indexPath.row];
  5. }
  6. }
  7.  
  8. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  9. WelfareItem *item = nil;
  10. if (indexPath.row < [_datasourceArray count]) {
  11. item = [_datasourceArray objectAtIndex:indexPath.row];
  12. }
  13. }

问题又来了,不管你武功有多高。有时也会忘记加。所以我们要想一招制敌办法。我是想到了用Runtime把objectAtIndex方法替换一下。代码例如以下:

  1. /*!
  2. @category
  3. @abstract NSObject的Category
  4. */
  5. @interface NSObject (Util)
  6.  
  7. /*!
  8. @method swizzleMethod:withMethod:error:
  9. @abstract 对实例方法进行替换
  10. @param oldSelector 想要替换的方法
  11. @param newSelector 实际替换为的方法
  12. @param error 替换过程中出现的错误,假设没有错误为nil
  13. */
  14. + (BOOL)swizzleMethod:(SEL)originalSelector withMethod:(SEL)swizzledSelector error:(NSError **)error;
  15.  
  16. @end
  17.  
  18. #import "NSObject+Util.h"
  19. #import <objc/runtime.h>
  20.  
  21. @implementation NSObject (Util)
  22.  
  23. + (BOOL)swizzleMethod:(SEL)originalSelector withMethod:(SEL)swizzledSelector error:(NSError **)error
  24. {
  25. Method originalMethod = class_getInstanceMethod(self, originalSelector);
  26. if (!originalMethod) {
  27. NSString *string = [NSString stringWithFormat:@" %@ 类没有找到 %@ 方法",NSStringFromClass([self class]),NSStringFromSelector(originalSelector)];
  28. *error = [NSError errorWithDomain:@"NSCocoaErrorDomain" code:-1 userInfo:[NSDictionary dictionaryWithObject:string forKey:NSLocalizedDescriptionKey]];
  29. return NO;
  30. }
  31.  
  32. Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
  33. if (!swizzledMethod) {
  34. NSString *string = [NSString stringWithFormat:@" %@ 类没有找到 %@ 方法",NSStringFromClass([self class]),NSStringFromSelector(swizzledSelector)];
  35. *error = [NSError errorWithDomain:@"NSCocoaErrorDomain" code:-1 userInfo:[NSDictionary dictionaryWithObject:string forKey:NSLocalizedDescriptionKey]];
  36. return NO;
  37. }
  38.  
  39. if (class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
  40. class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
  41. }
  42. else {
  43. method_exchangeImplementations(originalMethod, swizzledMethod);
  44. }
  45.  
  46. return YES;
  47. }
  48.  
  49. @end
  50.  
  51. @implementation NSArray (ErrerManager)
  52.  
  53. + (void)load
  54. {
  55. static dispatch_once_t onceToken;
  56. dispatch_once(&onceToken, ^{
  57. @autoreleasepool
  58. {
  59. [objc_getClass("__NSArrayI") swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(swizzleObjectAtIndex:) error:nil];
  60. [objc_getClass("__NSArrayM") swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(swizzleObjectAtIndex:) error:nil];
  61. };
  62. });
  63. }
  64.  
  65. - (id)swizzleObjectAtIndex:(NSUInteger)index
  66. {
  67. if (index < self.count)
  68. {
  69. return [self swizzleObjectAtIndex:index];
  70. }
  71. NSLog(@"%@ 越界",self);
  72. return nil;//越界返回为nil
  73. }
  74.  
  75. @end

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

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

  1. 1 tbreader 0x002b93e9 tbreader + 2098153
  2. 2 libsystem_platform.dylib 0x33a66873 _sigtramp + 34
  3. 3 libsystem_blocks.dylib 0x33941ae1 _Block_release + 216
  4. 4 libobjc.A.dylib 0x333c11a9 + 404
  5. 5 CoreFoundation 0x25ba23a9 _CFAutoreleasePoolPop + 16
  6. 6 UIKit 0x2912317f + 42
  7. 7 CoreFoundation 0x25c565cd + 20
  8. 8 CoreFoundation 0x25c53c8b + 278
  9. 9 CoreFoundation 0x25c54093 + 914
  10. 10 CoreFoundation 0x25ba2621 CFRunLoopRunSpecific + 476
  11. 11 CoreFoundation 0x25ba2433 CFRunLoopRunInMode + 106
  12. 12 GraphicsServices 0x2cf0a0a9 GSEventRunModal + 136
  13. 13 UIKit 0x2918c809 UIApplicationMain + 1440

都是这个Crash。出如今iOS7以上(含iOS7),关键还没实用户反馈有问题,Crash高了几倍没有一个用户反馈这样的情况还是少见的,大家測试还复现不了;測试了一周最终复现了一样的Crash;是这样出现的。替换了objectAtIndex方法有输入的地方出来了软键盘按手机Home键就Crash了;此法不行仅仅,仅仅能另寻他策了。

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

  1. @interface NSArray (SHYUtil)
  2.  
  3. /*!
  4. @method objectAtIndexCheck:
  5. @abstract 检查是否越界和NSNull假设是返回nil
  6. @result 返回对象
  7. */
  8. - (id)objectAtIndexCheck:(NSUInteger)index;
  9.  
  10. @end
  11.  
  12. #import "NSArray+SHYUtil.h"
  13.  
  14. @implementation NSArray (SHYUtil)
  15.  
  16. - (id)objectAtIndexCheck:(NSUInteger)index
  17. {
  18. if (index >= [self count]) {
  19. return nil;
  20. }
  21.  
  22. id value = [self objectAtIndex:index];
  23. if (value == [NSNull null]) {
  24. return nil;
  25. }
  26. return value;
  27. }
  28.  
  29. @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. 浅谈HTTP中Get与Post的区别/HTTP协议与HTML表单(再谈GET与POST的区别)

    HTTP协议与HTML表单(再谈GET与POST的区别) GET方式在request-line中传送数据:POST方式在request-line及request-body中均可以传送数据. http: ...

  2. 编写 Objective-C 代码

    如果您未曾开发过 iOS 或 Mac OS X 平台的程序,那就需要开始了解它们的首要程序设计语言 Objective-C.Objective-C 并不是一种很难的语言,如果能花一点时间学习,相信您会 ...

  3. JAVA实现word doc docx pdf excel的在线浏览 - 仿百度文库 源码

    我们具体实现思路是这样的 首先下载并安装openoffice和swftools openoffice下载地址:http://www.openoffice.org/download/index.html ...

  4. Visual Studio Solution Configuration

    https://msdn.microsoft.com/en-us/library/bb166577.aspx Solution configurations store solution-level ...

  5. URAL1029. Ministry(DP+路径)

    链接 路径麻烦啊 很多细节 倒回去搜一遍 卡了一节数据库.. #include <iostream> #include<cstdio> #include<cstring& ...

  6. 普通pc电脑安装苹果系统mac_详细教程(精)附带所有工具下载

    苹果操作系统只允许在苹果电脑上面安装和使用.和Windows不一样,要在PC上安装,需要一系列的模拟和破解.破解安装的过程很繁琐而具有挑战性,以下是安装10A432雪豹的PC安装指南,附带25张图片帮 ...

  7. wildfly-9.0.2 web项目部署详细步骤

    一.配置操作系统环境变量 JAVA_HOME = C:\Program Files (x86)\Java\jdk1.7.0_67 JBOSS_HOME = F:\server\wildfly-9.0. ...

  8. 【转】CString类型互转 int

    CString类型互转 int 原文网址:http://www.cnitblog.com/Hali/archive/2009/06/25/59632.html CString类型的转换成int  将字 ...

  9. JQuery datepicker 用法

    JQuery datepicker 用法   jQuery UI很强大,其中的日期选择插件Datepicker是一个配置灵活的插件,我们可以自定义其展示方式,包括日期格式.语言.限制选择日期范围.添加 ...

  10. jQuery append xmlNode 修改 xml 内容

    jQuery append xmlNode 修改 xml 内容 http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/04/29/jqu ...