用Method Swizzling来避免数组越界与可变字典value值为nil造成的程序崩溃

程序崩溃对于app来说是最致命的bug,而数组越界便是其中最重要的原因之一。我们可以应用Method Swizzling知识来避免这一问题。

1.我们来创建一个类别,继承于NSArray:




2.然后在.m文件中导入 objc/runtime.h头文件

#import "NSArray+EM.h"
#import <objc/runtime.h>

@implementation NSArray (EM)
+(void)load {
    Method fromMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:));
    Method toMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(em_objectAtIndex:));
    method_exchangeImplementations(fromMethod, toMethod);
}

- (void)em_objectAtIndex:(NSUInteger)index {
    if (self.count - 1 < index) {
        @try {
            return[self em_objectAtIndex:index];
        }
        @catch (NSException *exception) {
            NSLog(@"-------- %s Crash Because Method %s -------\n",class_getName(self.class),__func__);
            NSLog(@"%@", [exception callStackSymbols]);
        }
        @finally {
            
        }
    }else {
        return [self em_objectAtIndex:index];
    }
}
@end


细心的人会发现,下面这个方法会导致递归,其实不会的。

这实际上是运用了方法替换,当我们在其他类中 调用NSArray的objectAtIndex方法时,会被自动替换为执行em_objectAtIndex:方法,而当我们调用em_objectAtIndex:方法时,会被替换为执行objectAtIndex:方法。

我们也可以用这种方法同样解决NSMutableArray。

#import "NSMutableArray+EM.h"
#import <objc/runtime.h>
@implementation NSMutableArray (EM)
+(void)load {
    Method fromMethod = class_getInstanceMethod(objc_getClass("__NSArrayM"), @selector(objectAtIndex:));
    Method toMethod = class_getInstanceMethod(objc_getClass("__NSArrayM"), @selector(em_objectAtIndex:));
    method_exchangeImplementations(fromMethod, toMethod);
    
}

- (void)em_objectAtIndex:(NSUInteger)index {
    if (self.count - 1 < index) {
        @try {
            return[self em_objectAtIndex:index];
        }
        @catch (NSException *exception) {
            NSLog(@"-------- %s Crash Because Method %s -------\n",class_getName(self.class),__func__);
            NSLog(@"%@", [exception callStackSymbols]);
        }
        @finally {
            
        }
    }else {
        return [self em_objectAtIndex:index];
    }
}

@end


还可以判断NSMutableDictionary 的value值是否为nil

#import "NSMutableDictionary+EM.h"
#import <objc/runtime.h>
@implementation NSMutableDictionary (EM)
+ (void)load {
    
    Method fromMethod = class_getInstanceMethod(objc_getClass("__NSDictionaryM"), @selector(setObject:forKey:));
    Method toMethod = class_getInstanceMethod(objc_getClass("__NSDictionaryM"), @selector(em_setObject:forKey:));
    method_exchangeImplementations(fromMethod, toMethod);
}

- (void)em_setObject:(id)emObject forKey:(NSString *)key {
    if (emObject == nil) {
        @try {
            [self em_setObject:emObject forKey:key];
        }
        @catch (NSException *exception) {
            NSLog(@"---------- %s Crash Because Method %s  ----------\n", class_getName(self.class), __func__);
            NSLog(@"%@", [exception callStackSymbols]);
            emObject = [NSString stringWithFormat:@""];
            [self em_setObject:emObject forKey:key];
        }
        @finally {}
    }else {
        [self em_setObject:emObject forKey:key];
    }
}
@end


下面我们列举一些常用的类簇的“真身”:




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值