iOS 數組越界 Crash處理經驗

來源:互聯網
上載者:User

iOS 數組越界 Crash處理經驗

我們先來看看有可能會出現的數組越界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 @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 + 20981532 libsystem_platform.dylib 0x33a66873 _sigtramp + 343 libsystem_blocks.dylib 0x33941ae1 _Block_release + 2164 libobjc.A.dylib 0x333c11a9 + 4045 CoreFoundation 0x25ba23a9 _CFAutoreleasePoolPop + 166 UIKit 0x2912317f + 427 CoreFoundation 0x25c565cd + 208 CoreFoundation 0x25c53c8b + 2789 CoreFoundation 0x25c54093 + 91410 CoreFoundation 0x25ba2621 CFRunLoopRunSpecific + 47611 CoreFoundation 0x25ba2433 CFRunLoopRunInMode + 10612 GraphicsServices 0x2cf0a0a9 GSEventRunModal + 13613 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]' 錯誤了

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.