概述
我们先来看看有可能会出现的数组越界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;解决这个问题也很简单代码如下:
- - (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
- @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
最后
以上就是温暖汽车为你收集整理的iOS 数组越界 Crash处理经验的全部内容,希望文章能够帮你解决iOS 数组越界 Crash处理经验所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复