Files
mier_ios/SweetParty/第三方库/AvoidCrash/NSObject+AvoidCrash.m
2025-08-11 10:43:19 +08:00

222 lines
8.0 KiB
Objective-C

//
// NSObject+AvoidCrash.m
// https://github.com/chenfanfang/AvoidCrash
//
// Created by mac on 16/10/11.
// Copyright © 2016年 chenfanfang. All rights reserved.
//
#import "NSObject+AvoidCrash.h"
#import "AvoidCrash.h"
#import "AvoidCrashStubProxy.h"
@implementation NSObject (AvoidCrash)
+ (void)avoidCrashExchangeMethodIfDealWithNoneSel:(BOOL)ifDealWithNoneSel {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//setValue:forKey:
[AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValue:forKey:) method2Sel:@selector(avoidCrashSetValue:forKey:)];
//setValue:forKeyPath:
[AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValue:forKeyPath:) method2Sel:@selector(avoidCrashSetValue:forKeyPath:)];
//setValue:forUndefinedKey:
[AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValue:forUndefinedKey:) method2Sel:@selector(avoidCrashSetValue:forUndefinedKey:)];
//setValuesForKeysWithDictionary:
[AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValuesForKeysWithDictionary:) method2Sel:@selector(avoidCrashSetValuesForKeysWithDictionary:)];
//unrecognized selector sent to instance
if (ifDealWithNoneSel) {
[AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(methodSignatureForSelector:) method2Sel:@selector(avoidCrashMethodSignatureForSelector:)];
[AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(forwardInvocation:) method2Sel:@selector(avoidCrashForwardInvocation:)];
}
});
}
//=================================================================
// unrecognized selector sent to instance
//=================================================================
#pragma mark - unrecognized selector sent to instance
static NSMutableArray *noneSelClassStrings;
static NSMutableArray *noneSelClassStringPrefixs;
+ (void)setupNoneSelClassStringsArr:(NSArray<NSString *> *)classStrings {
if (noneSelClassStrings) {
NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringsArr:];\n调用一此即可,多次调用会自动忽略后面的调用\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator];
AvoidCrashLog(@"%@",warningMsg);
}
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
noneSelClassStrings = [NSMutableArray array];
for (NSString *className in classStrings) {
if ([className hasPrefix:@"UI"] == NO &&
[className isEqualToString:NSStringFromClass([NSObject class])] == NO) {
[noneSelClassStrings addObject:className];
} else {
NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringsArr:];\n会忽略UI开头的类和NSObject类(请使用NSObject的子类)\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator];
AvoidCrashLog(@"%@",warningMsg);
}
}
});
}
/**
* 初始化一个需要防止”unrecognized selector sent to instance”的崩溃的类名前缀的数组
*/
+ (void)setupNoneSelClassStringPrefixsArr:(NSArray<NSString *> *)classStringPrefixs {
if (noneSelClassStringPrefixs) {
NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringPrefixsArr:];\n调用一此即可,多次调用会自动忽略后面的调用\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator];
AvoidCrashLog(@"%@",warningMsg);
}
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
noneSelClassStringPrefixs = [NSMutableArray array];
for (NSString *classNamePrefix in classStringPrefixs) {
if ([classNamePrefix hasPrefix:@"UI"] == NO &&
[classNamePrefix hasPrefix:@"NS"] == NO) {
[noneSelClassStringPrefixs addObject:classNamePrefix];
} else {
NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringsArr:];\n会忽略UI开头的类和NS开头的类\n若需要对NS开头的类防止”unrecognized selector sent to instance”(比如NSArray),请使用setupNoneSelClassStringsArr:\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator];
AvoidCrashLog(@"%@",warningMsg);
}
}
});
}
- (NSMethodSignature *)avoidCrashMethodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *ms = [self avoidCrashMethodSignatureForSelector:aSelector];
BOOL flag = NO;
if (ms == nil) {
for (NSString *classStr in noneSelClassStrings) {
if ([self isKindOfClass:NSClassFromString(classStr)]) {
ms = [AvoidCrashStubProxy instanceMethodSignatureForSelector:@selector(proxyMethod)];
flag = YES;
break;
}
}
}
if (flag == NO) {
NSString *selfClass = NSStringFromClass([self class]);
for (NSString *classStrPrefix in noneSelClassStringPrefixs) {
if ([selfClass hasPrefix:classStrPrefix]) {
ms = [AvoidCrashStubProxy instanceMethodSignatureForSelector:@selector(proxyMethod)];
}
}
}
return ms;
}
- (void)avoidCrashForwardInvocation:(NSInvocation *)anInvocation {
@try {
[self avoidCrashForwardInvocation:anInvocation];
} @catch (NSException *exception) {
NSString *defaultToDo = AvoidCrashDefaultIgnore;
[AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
} @finally {
}
}
//=================================================================
// setValue:forKey:
//=================================================================
#pragma mark - setValue:forKey:
- (void)avoidCrashSetValue:(id)value forKey:(NSString *)key {
@try {
[self avoidCrashSetValue:value forKey:key];
}
@catch (NSException *exception) {
NSString *defaultToDo = AvoidCrashDefaultIgnore;
[AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
}
@finally {
}
}
//=================================================================
// setValue:forKeyPath:
//=================================================================
#pragma mark - setValue:forKeyPath:
- (void)avoidCrashSetValue:(id)value forKeyPath:(NSString *)keyPath {
@try {
[self avoidCrashSetValue:value forKeyPath:keyPath];
}
@catch (NSException *exception) {
NSString *defaultToDo = AvoidCrashDefaultIgnore;
[AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
}
@finally {
}
}
//=================================================================
// setValue:forUndefinedKey:
//=================================================================
#pragma mark - setValue:forUndefinedKey:
- (void)avoidCrashSetValue:(id)value forUndefinedKey:(NSString *)key {
@try {
[self avoidCrashSetValue:value forUndefinedKey:key];
}
@catch (NSException *exception) {
NSString *defaultToDo = AvoidCrashDefaultIgnore;
[AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
}
@finally {
}
}
//=================================================================
// setValuesForKeysWithDictionary:
//=================================================================
#pragma mark - setValuesForKeysWithDictionary:
- (void)avoidCrashSetValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues {
@try {
[self avoidCrashSetValuesForKeysWithDictionary:keyedValues];
}
@catch (NSException *exception) {
NSString *defaultToDo = AvoidCrashDefaultIgnore;
[AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
}
@finally {
}
}
@end