runtime解决iOS开发中数组越界致使crash问题

1、什么是数组越界

数组越界,不少新手容易中招的bug,数组

NSArray *ar = @[@"123", @(456), @"haha"];
nsstring *str = ar[3];//数组取值越界了
复制代码

这个看起来很简单,可是实际开发应用中,各类数据变量在程序运行过程当中,是常常不断变化的,很容易被忽视,一不当心就越界致使crash。咱们先不论为何越界,这是另外一个议题,至少最基本的咱们要先保证程序不会奔溃是吧。服务器

2、数组越界最简单的一种解决方案,固然就是取值的时候限制下index的值,好比:

NSArray *moduleTexts = @[@"资讯系统", @"数字资源", @"震例系统", @"百科系统"];
int index = self.moduleCode.intValue-1;//moduleCode是服务器返回值,NSString类型
index = MAX(MIN(index, 3), 0);
lb_moduleType.text = moduleTexts[index];
复制代码

3、在数组的分类中使用runtime机制来交换方法

基本思路是:当数组越界时返回nil,没有越界时返回本来的index.这样就能达到防止程序崩溃的问题.ui

一、建立NSObject的Category分类

此分类文件就一个方法,该方法用runtime的机制来替换系统方法。spa

NSObject+ExchangeMethod.h文件:code

#import <Foundation/Foundation.h>
@interface NSObject (ExchangeMethod)

/** * 对系统方法进行替换(交换实例方法) * * @param systemSelector 被替换的方法 * @param changedSelector 实际使用的方法 * @param error 替换过程当中出现的错误消息 * * @return 是否替换成功 */
+ (BOOL)exchangedSystemSelector:(SEL)systemSelector withSelector:(SEL)changedSelector error:(NSError *)error;

@end
复制代码

建立.m文件NSObject+ExchangeMethod.m:ip

#import "NSObject+ExchangeMethod.h"
#import <objc/runtime.h>

@implementation NSObject (ExchangeMethod)
+ (BOOL)exchangedSystemSelector:(SEL)systemSelector withSelector:(SEL)changedSelector error:(NSError *)error{

    Method systemMethod = class_getInstanceMethod(self, systemSelector);
    if (!systemMethod) {
        return NO;
    }

    Method changedMethod = class_getInstanceMethod(self, changedSelector);
    if (!changedMethod) {
        return NO;
    }

    if (class_addMethod([self class], systemSelector, method_getImplementation(changedMethod), method_getTypeEncoding(changedMethod))) {
        class_replaceMethod([self class], changedSelector, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));
    }else{
        method_exchangeImplementations(systemMethod, changedMethod);
    }

    return YES;
}
@end
复制代码

二、建立NSArray的分类,

NSArray+Overflow.h文件:资源

#import <objc/runtime.h>
#import <Foundation/Foundation.h>

@interface NSArray (Overflow)

@end

复制代码

NSArray+Overflow.m文件:开发

#import "NSArray+Overflow.h"
#import "NSObject+ExchangeMethod.h"
#import <objc/runtime.h>

@implementation NSArray (Overflow)

+(void)load{
    [super load];
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [objc_getClass("__NSArrayI") exchangedSystemSelector:@selector(objectAtIndex:) withSelector:@selector(hd_objectAtIndex:) error:nil];
        [objc_getClass("__NSArrayI") exchangedSystemSelector:@selector(objectAtIndexedSubscript:) withSelector:@selector(hd_objectAtIndexedSubscript:) error:nil];
    });
}
- (id)sxy_objectAtIndexedSubscript:(NSUInteger)index{
    if (index < self.count) {
        return [self hd_objectAtIndexedSubscript:index];
    }else{
        NSLog(@"Error:数组越界了,index = %ld, count = %ld", index, self.count);
        return nil;
    }
}

- (id)sxy_objectAtIndex:(NSUInteger)index{
    if (index < self.count) {
        return [self hd_objectAtIndex:index];
    }else{
        NSLog(@"Error:数组越界了,index = %ld, count = %ld", index, self.count);
        return nil;
    }
}
@end
复制代码

三、建立NSMutabeArray的分类,

NSMutableArray+Overflow.h文件:get

#import <Foundation/Foundation.h>

@interface NSMutableArray (Overflow)

@end
复制代码

NSMutableArray+Overflow.m文件:string

#import "NSMutableArray+Overflow.h"
#import "NSObject+ExchangeMethod.h"

@implementation NSMutableArray (Overflow)
+(void)load{
    [super load];
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [objc_getClass("__NSArrayM") exchangedSystemSelector:@selector(objectAtIndex:) withSelector:@selector(hd_objectAtIndex:) error:nil];
        [objc_getClass("__NSArrayM") exchangedSystemSelector:@selector(objectAtIndexedSubscript:) withSelector:@selector(hd_objectAtIndexedSubscript:) error:nil];
    });
}
- (id)hd_objectAtIndexedSubscript:(NSUInteger)idx{
    if (idx < self.count) {
        return [self hd_objectAtIndexedSubscript:idx];
    }else{
        NSLog(@"Error:数组越界了,index = %ld, count = %ld", idx, self.count);
        return nil;
    }
}

- (id)hd_objectAtIndex:(NSUInteger)index{
    if (index < self.count) {
        return [self hd_objectAtIndex:index];
    }else{
        NSLog(@"Error:数组越界了,index = %ld, count = %ld", index, self.count);
        return nil;
    }
}
@end
复制代码

四、最后在项目工程下XXXX-Prefix.pch文件里添加NSArray和NSMutableAray的分类头文件就好了:

#ifdef __OBJC__
#define MAS_SHORTHAND

#import "NSArray+overflow.h"
#import "NSMutableArray+Overflow.h"

#endif
复制代码
相关文章
相关标签/搜索