您的位置:首页 > 移动开发 > Objective-C

数组越界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]' 错误了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息