数组越界Crash
2016-07-25 14:39
501 查看
问题又来了,无论你武功有多高,有时也会忘记加;所以我们要想一招制敌办法;我是想到了用Runtime把objectAtIndex方法替换一下;代码如下:
[objc] view
plain copy
/*!
@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如下
[plain] view
plain copy
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了;此法不行只,只能另寻他策了。后来我们就给数组新增扩展方法代码如下
[objc] view
plain copy
@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]' 错误了
[objc] view
plain copy
/*!
@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如下
[plain] view
plain copy
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了;此法不行只,只能另寻他策了。后来我们就给数组新增扩展方法代码如下
[objc] view
plain copy
@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开发之路--微博“更多”页面
- Objective-C的内省(Introspection)用法小结
- Objective-C中常用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect实例分析
- Objective-C中使用NSString类操作字符串的方法小结
- iOS开发之路--微博骨架搭建
- iOS开发使用JSON解析网络数据
- Objective-C中NSNumber与NSDictionary的用法简介
- IOS开发代码分享之获取启动画面图片的string
- Objective-C实现冒泡排序算法的简单示例
- Objective-C中NSLog输出格式大全
- Objective-C实现自定义的半透明导航
- iOS开发实现音频播放功能
- iOS开发之视图切换
- 浅析Objective-C的程序结构及面向对象的编程方式
- iOS开发使用XML解析网络数据
- IOS开发实现录音功能
- searchDisplayController 引起的数组越界处理办法
- Objective-C的入门学习笔记
- Objective-C实现无限循环轮播器
- iOS开发之UIScrollView详解