From a7a826d4569db0d4ba4fd3b944447adbce3f3608 Mon Sep 17 00:00:00 2001 From: lspo9419 Date: Tue, 30 Nov 2021 11:51:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=20=E5=B4=A9?= =?UTF-8?q?=E6=BA=83=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FXZRedoVendor.podspec | 4 + .../Classes/FXZYCrashHandle/JRSwizzle.h | 48 +++++ .../Classes/FXZYCrashHandle/JRSwizzle.m | 166 ++++++++++++++++++ .../FXZYCrashHandle/NSArray+GHLCrashGuard.h | 16 ++ .../FXZYCrashHandle/NSArray+GHLCrashGuard.m | 71 ++++++++ .../NSDictionary+GHLCrashGuard.h | 16 ++ .../NSDictionary+GHLCrashGuard.m | 31 ++++ .../NSMutableArray+GHLCrashGuard.h | 16 ++ .../NSMutableArray+GHLCrashGuard.m | 83 +++++++++ .../NSMutableDictionary+GHLCrashGuard.h | 16 ++ .../NSMutableDictionary+GHLCrashGuard.m | 50 ++++++ .../FXZYCrashHandle/NSObject+Selector.h | 17 ++ .../FXZYCrashHandle/NSObject+Selector.m | 89 ++++++++++ 13 files changed, 623 insertions(+) create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/JRSwizzle.h create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/JRSwizzle.m create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSArray+GHLCrashGuard.h create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSArray+GHLCrashGuard.m create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSDictionary+GHLCrashGuard.h create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSDictionary+GHLCrashGuard.m create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableArray+GHLCrashGuard.h create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableArray+GHLCrashGuard.m create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableDictionary+GHLCrashGuard.h create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableDictionary+GHLCrashGuard.m create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSObject+Selector.h create mode 100644 FXZRedoVendor/Classes/FXZYCrashHandle/NSObject+Selector.m diff --git a/FXZRedoVendor.podspec b/FXZRedoVendor.podspec index 4da66d0..75b9fea 100644 --- a/FXZRedoVendor.podspec +++ b/FXZRedoVendor.podspec @@ -50,6 +50,10 @@ TODO: Add long description of the pod here. ss.source_files = 'FXZRedoVendor/Classes/RatingBar/*' end + s.subspec 'FXZYCrashHandle' do |ss| + ss.source_files = 'FXZRedoVendor/Classes/FXZYCrashHandle/*' + end + # s.resource_bundles = { diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/JRSwizzle.h b/FXZRedoVendor/Classes/FXZYCrashHandle/JRSwizzle.h new file mode 100644 index 0000000..f8a0aaf --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/JRSwizzle.h @@ -0,0 +1,48 @@ +// JRSwizzle.h semver:1.1.0 +// Copyright (c) 2007-2016 Jonathan 'Wolf' Rentzsch: http://rentzsch.com +// Some rights reserved: http://opensource.org/licenses/mit +// https://github.com/rentzsch/jrswizzle + +#import + +@interface NSObject (JRSwizzle) + ++ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_; ++ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_; + + +/** + ``` + __block NSInvocation *invocation = nil; + invocation = [self jr_swizzleMethod:@selector(initWithCoder:) withBlock:^(id obj, NSCoder *coder) { + NSLog(@"before %@, coder %@", obj, coder); + + [invocation setArgument:&coder atIndex:2]; + [invocation invokeWithTarget:obj]; + + id ret = nil; + [invocation getReturnValue:&ret]; + + NSLog(@"after %@, coder %@", obj, coder); + + return ret; + } error:nil]; + ``` + */ ++ (NSInvocation*)jr_swizzleMethod:(SEL)origSel withBlock:(id)block error:(NSError**)error; + +/** + ``` + __block NSInvocation *classInvocation = nil; + classInvocation = [self jr_swizzleClassMethod:@selector(test) withBlock:^() { + NSLog(@"before"); + + [classInvocation invoke]; + + NSLog(@"after"); + } error:nil]; + ``` + */ ++ (NSInvocation*)jr_swizzleClassMethod:(SEL)origSel withBlock:(id)block error:(NSError**)error; + +@end diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/JRSwizzle.m b/FXZRedoVendor/Classes/FXZYCrashHandle/JRSwizzle.m new file mode 100644 index 0000000..d130bb5 --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/JRSwizzle.m @@ -0,0 +1,166 @@ +// JRSwizzle.m semver:1.1.0 +// Copyright (c) 2007-2016 Jonathan 'Wolf' Rentzsch: http://rentzsch.com +// Some rights reserved: http://opensource.org/licenses/mit +// https://github.com/rentzsch/jrswizzle + +#import "JRSwizzle.h" + +#if TARGET_OS_IPHONE + #import + #import +#else + #import +#endif + +#define SetNSErrorFor(FUNC, ERROR_VAR, FORMAT,...) \ + if (ERROR_VAR) { \ + NSString *errStr = [NSString stringWithFormat:@"%s: " FORMAT,FUNC,##__VA_ARGS__]; \ + *ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \ + code:-1 \ + userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \ + } +#define SetNSError(ERROR_VAR, FORMAT,...) SetNSErrorFor(__func__, ERROR_VAR, FORMAT, ##__VA_ARGS__) + +#if OBJC_API_VERSION >= 2 +#define GetClass(obj) object_getClass(obj) +#else +#define GetClass(obj) (obj ? obj->isa : Nil) +#endif + +@implementation NSObject (JRSwizzle) + ++ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_ { +#if OBJC_API_VERSION >= 2 + Method origMethod = class_getInstanceMethod(self, origSel_); + if (!origMethod) { +#if TARGET_OS_IPHONE + SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self class]); +#else + SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); +#endif + return NO; + } + + Method altMethod = class_getInstanceMethod(self, altSel_); + if (!altMethod) { +#if TARGET_OS_IPHONE + SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self class]); +#else + SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); +#endif + return NO; + } + + class_addMethod(self, + origSel_, + class_getMethodImplementation(self, origSel_), + method_getTypeEncoding(origMethod)); + class_addMethod(self, + altSel_, + class_getMethodImplementation(self, altSel_), + method_getTypeEncoding(altMethod)); + + method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_)); + return YES; +#else + // Scan for non-inherited methods. + Method directOriginalMethod = NULL, directAlternateMethod = NULL; + + void *iterator = NULL; + struct objc_method_list *mlist = class_nextMethodList(self, &iterator); + while (mlist) { + int method_index = 0; + for (; method_index < mlist->method_count; method_index++) { + if (mlist->method_list[method_index].method_name == origSel_) { + assert(!directOriginalMethod); + directOriginalMethod = &mlist->method_list[method_index]; + } + if (mlist->method_list[method_index].method_name == altSel_) { + assert(!directAlternateMethod); + directAlternateMethod = &mlist->method_list[method_index]; + } + } + mlist = class_nextMethodList(self, &iterator); + } + + // If either method is inherited, copy it up to the target class to make it non-inherited. + if (!directOriginalMethod || !directAlternateMethod) { + Method inheritedOriginalMethod = NULL, inheritedAlternateMethod = NULL; + if (!directOriginalMethod) { + inheritedOriginalMethod = class_getInstanceMethod(self, origSel_); + if (!inheritedOriginalMethod) { +#if TARGET_OS_IPHONE + SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self class]); +#else + SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); +#endif + return NO; + } + } + if (!directAlternateMethod) { + inheritedAlternateMethod = class_getInstanceMethod(self, altSel_); + if (!inheritedAlternateMethod) { +#if TARGET_OS_IPHONE + SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self class]); +#else + SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); +#endif + return NO; + } + } + + int hoisted_method_count = !directOriginalMethod && !directAlternateMethod ? 2 : 1; + struct objc_method_list *hoisted_method_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)*(hoisted_method_count-1))); + hoisted_method_list->obsolete = NULL; // soothe valgrind - apparently ObjC runtime accesses this value and it shows as uninitialized in valgrind + hoisted_method_list->method_count = hoisted_method_count; + Method hoisted_method = hoisted_method_list->method_list; + + if (!directOriginalMethod) { + bcopy(inheritedOriginalMethod, hoisted_method, sizeof(struct objc_method)); + directOriginalMethod = hoisted_method++; + } + if (!directAlternateMethod) { + bcopy(inheritedAlternateMethod, hoisted_method, sizeof(struct objc_method)); + directAlternateMethod = hoisted_method; + } + class_addMethods(self, hoisted_method_list); + } + + // Swizzle. + IMP temp = directOriginalMethod->method_imp; + directOriginalMethod->method_imp = directAlternateMethod->method_imp; + directAlternateMethod->method_imp = temp; + + return YES; +#endif +} + ++ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ { + return [GetClass((id)self) jr_swizzleMethod:origSel_ withMethod:altSel_ error:error_]; +} + ++ (NSInvocation*)jr_swizzleMethod:(SEL)origSel withBlock:(id)block error:(NSError**)error { + IMP blockIMP = imp_implementationWithBlock(block); + NSString *blockSelectorString = [NSString stringWithFormat:@"_jr_block_%@_%p", NSStringFromSelector(origSel), block]; + SEL blockSel = sel_registerName([blockSelectorString cStringUsingEncoding:NSUTF8StringEncoding]); + Method origSelMethod = class_getInstanceMethod(self, origSel); + const char* origSelMethodArgs = method_getTypeEncoding(origSelMethod); + class_addMethod(self, blockSel, blockIMP, origSelMethodArgs); + + NSMethodSignature *origSig = [NSMethodSignature signatureWithObjCTypes:origSelMethodArgs]; + NSInvocation *origInvocation = [NSInvocation invocationWithMethodSignature:origSig]; + origInvocation.selector = blockSel; + + [self jr_swizzleMethod:origSel withMethod:blockSel error:nil]; + + return origInvocation; +} + ++ (NSInvocation*)jr_swizzleClassMethod:(SEL)origSel withBlock:(id)block error:(NSError**)error { + NSInvocation *invocation = [GetClass((id)self) jr_swizzleMethod:origSel withBlock:block error:error]; + invocation.target = self; + + return invocation; +} + +@end diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSArray+GHLCrashGuard.h b/FXZRedoVendor/Classes/FXZYCrashHandle/NSArray+GHLCrashGuard.h new file mode 100644 index 0000000..4799549 --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSArray+GHLCrashGuard.h @@ -0,0 +1,16 @@ +// +// NSArray+GHLCrashGuard.h +// GHLCrashGuard +// +// Created by 与佳期 on 2019/7/11. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSArray (GHLCrashGuard) + +@end + +NS_ASSUME_NONNULL_END diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSArray+GHLCrashGuard.m b/FXZRedoVendor/Classes/FXZYCrashHandle/NSArray+GHLCrashGuard.m new file mode 100644 index 0000000..843490e --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSArray+GHLCrashGuard.m @@ -0,0 +1,71 @@ +// +// NSArray+GHLCrashGuard.m +// GHLCrashGuard +// +// Created by 与佳期 on 2019/7/11. +// + +#import "NSArray+GHLCrashGuard.h" +#import "JRSwizzle.h" + +@implementation NSArray (GHLCrashGuard) + ++ (void)load { + + // [NSArray alloc] + [NSClassFromString(@"__NSPlaceholderArray") jr_swizzleMethod:@selector(initWithObjects:count:) withMethod:@selector(initWithObjects_guard:count:) error:nil]; + // @[] + [NSClassFromString(@"__NSArray0") jr_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(guard_objectAtIndex:) error:nil]; + [NSClassFromString(@"__NSArray0") jr_swizzleMethod:@selector(arrayByAddingObject:) withMethod:@selector(guard_arrayByAddingObject:) error:nil]; + // @[@1] + [NSClassFromString(@"__NSSingleObjectArrayI") jr_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(guard_objectAtIndex:) error:nil]; + [NSClassFromString(@"__NSSingleObjectArrayI") jr_swizzleMethod:@selector(arrayByAddingObject:) withMethod:@selector(guard_arrayByAddingObject:) error:nil]; + // @[@1, @2] + [NSClassFromString(@"__NSArrayI") jr_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(guard_objectAtIndex:) error:nil]; + [NSClassFromString(@"__NSArrayI") jr_swizzleMethod:@selector(arrayByAddingObject:) withMethod:@selector(guard_arrayByAddingObject:) error:nil]; +} + +- (instancetype)initWithObjects_guard:(id *)objects count:(NSUInteger)cnt { + NSUInteger newCnt = 0; + for (NSUInteger i = 0; i < cnt; i++) { + if (!objects[i]) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + break; + } + newCnt++; + } + self = [self initWithObjects_guard:objects count:newCnt]; + return self; +} + +- (id)guard_objectAtIndex:(NSUInteger)index { + if (index >= [self count]) { + // 收集堆栈,上报 Crash + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return nil; + } + return [self guard_objectAtIndex:index]; +} + +- (NSArray *)guard_arrayByAddingObject:(id)anObject { + if (!anObject) { + + // 收集堆栈,上报 Crash + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return self; + } + return [self guard_arrayByAddingObject:anObject]; +} + ++ (void)warningDeveloper:(SEL)aSelector{ +#if DEBUG + + NSString *selectorStr = NSStringFromSelector(aSelector); + NSLog(@"PROTECTOR: -[%@ %@]", [self class], selectorStr); + NSLog(@"PROTECTOR: unrecognized selector \"%@\" sent to instance: %p", selectorStr, self); + NSLog(@"PROTECTOR: call stack: %@", [NSThread callStackSymbols]); + NSAssert(NO, @"arr调用方法出错---[%@-%@]", [self class], selectorStr); + // @throw @"方法找不到"; +#endif +} +@end diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSDictionary+GHLCrashGuard.h b/FXZRedoVendor/Classes/FXZYCrashHandle/NSDictionary+GHLCrashGuard.h new file mode 100644 index 0000000..322f5e6 --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSDictionary+GHLCrashGuard.h @@ -0,0 +1,16 @@ +// +// NSDictionary+GHLCrashGuard.h +// GHLCrashGuard +// +// Created by 与佳期 on 2019/7/11. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSDictionary (GHLCrashGuard) + +@end + +NS_ASSUME_NONNULL_END diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSDictionary+GHLCrashGuard.m b/FXZRedoVendor/Classes/FXZYCrashHandle/NSDictionary+GHLCrashGuard.m new file mode 100644 index 0000000..475be77 --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSDictionary+GHLCrashGuard.m @@ -0,0 +1,31 @@ +// +// NSDictionary+GHLCrashGuard.m +// GHLCrashGuard +// +// Created by 与佳期 on 2019/7/11. +// + +#import "NSDictionary+GHLCrashGuard.h" +#import "JRSwizzle.h" + +@implementation NSDictionary (GHLCrashGuard) + ++ (void)load { + + // [NSArray alloc] + [NSClassFromString(@"__NSPlaceholderArray") jr_swizzleMethod:@selector(initWithObjects:forKeys:count:) withMethod:@selector(initWithObjects_guard:forKeys:count:) error:nil]; +} + +- (instancetype)initWithObjects_guard:(id *)objects forKeys:(id *)keys count:(NSUInteger)cnt { + NSUInteger newCnt = 0; + for (NSUInteger i = 0; i < cnt; i++) { + if (!(keys[i] && objects[i])) { + break; + } + newCnt++; + } + self = [self initWithObjects_guard:objects forKeys:keys count:newCnt]; + return self; +} + +@end diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableArray+GHLCrashGuard.h b/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableArray+GHLCrashGuard.h new file mode 100644 index 0000000..795ae3a --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableArray+GHLCrashGuard.h @@ -0,0 +1,16 @@ +// +// NSMutableArray+GHLCrashGuard.h +// GHLCrashGuard +// +// Created by 与佳期 on 2019/7/11. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSMutableArray (GHLCrashGuard) + +@end + +NS_ASSUME_NONNULL_END diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableArray+GHLCrashGuard.m b/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableArray+GHLCrashGuard.m new file mode 100644 index 0000000..fe50d32 --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableArray+GHLCrashGuard.m @@ -0,0 +1,83 @@ +// +// NSMutableArray+GHLCrashGuard.m +// GHLCrashGuard +// +// Created by 与佳期 on 2019/7/11. +// + +#import "NSMutableArray+GHLCrashGuard.h" +#import "JRSwizzle.h" + +@implementation NSMutableArray (GHLCrashGuard) + ++ (void)load { + + [NSClassFromString(@"__NSArrayM") jr_swizzleMethod:@selector(addObject:) withMethod:@selector(guard_addObject:) error:nil]; + [NSClassFromString(@"__NSArrayM") jr_swizzleMethod:@selector(insertObject:atIndex:) withMethod:@selector(guard_insertObject:atIndex:) error:nil]; + [NSClassFromString(@"__NSArrayM") jr_swizzleMethod:@selector(removeObjectAtIndex:) withMethod:@selector(guard_removeObjectAtIndex:) error:nil]; + [NSClassFromString(@"__NSArrayM") jr_swizzleMethod:@selector(replaceObjectAtIndex:withObject:) withMethod:@selector(guard_replaceObjectAtIndex:withObject:) error:nil]; + [NSClassFromString(@"__NSArrayM") jr_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(guard_objectAtIndex:) error:nil]; +} + + +- (void)guard_addObject:(id)anObject { + if (!anObject) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return; + } + [self guard_addObject:anObject]; +} + +- (void)guard_insertObject:(id)anObject atIndex:(NSUInteger)index { + if (index > [self count]) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return; + } + if (!anObject) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return; + } + [self guard_insertObject:anObject atIndex:index]; +} + +- (void)guard_removeObjectAtIndex:(NSUInteger)index { + if (index >= [self count]) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return; + } + + return [self guard_removeObjectAtIndex:index]; +} +- (void)guard_replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { + if (index >= [self count]) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return; + } + if (!anObject) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return; + } + [self guard_replaceObjectAtIndex:index withObject:anObject]; +} + +- (id)guard_objectAtIndex:(NSUInteger)index { + if (index >= [self count]) { + // 收集堆栈,上报 Crash + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return nil; + } + return [self guard_objectAtIndex:index]; +} + ++ (void)warningDeveloper:(SEL)aSelector{ +#if DEBUG + + NSString *selectorStr = NSStringFromSelector(aSelector); + NSLog(@"PROTECTOR: -[%@ %@]", [self class], selectorStr); + NSLog(@"PROTECTOR: unrecognized selector \"%@\" sent to instance: %p", selectorStr, self); + NSLog(@"PROTECTOR: call stack: %@", [NSThread callStackSymbols]); + NSAssert(NO, @"marr调用出错---[%@-%@]", [self class], selectorStr); + // @throw @"方法找不到"; +#endif +} +@end diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableDictionary+GHLCrashGuard.h b/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableDictionary+GHLCrashGuard.h new file mode 100644 index 0000000..4895ff8 --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableDictionary+GHLCrashGuard.h @@ -0,0 +1,16 @@ +// +// NSMutableDictionary+GHLCrashGuard.h +// GHLCrashGuard +// +// Created by 与佳期 on 2019/7/11. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSMutableDictionary (GHLCrashGuard) + +@end + +NS_ASSUME_NONNULL_END diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableDictionary+GHLCrashGuard.m b/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableDictionary+GHLCrashGuard.m new file mode 100644 index 0000000..96318b5 --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSMutableDictionary+GHLCrashGuard.m @@ -0,0 +1,50 @@ +// +// NSMutableDictionary+GHLCrashGuard.m +// GHLCrashGuard +// +// Created by 与佳期 on 2019/7/11. +// + +#import "NSMutableDictionary+GHLCrashGuard.h" +#import "JRSwizzle.h" + +@implementation NSMutableDictionary (GHLCrashGuard) + ++ (void)load { + + [NSClassFromString(@"__NSDictionaryM") jr_swizzleMethod:@selector(removeObjectForKey:) withMethod:@selector(guard_removeObjectForKey:) error:nil]; + [NSClassFromString(@"__NSDictionaryM") jr_swizzleMethod:@selector(setObject:forKey:) withMethod:@selector(guard_setObject:forKey:) error:nil]; +} + +- (void)guard_removeObjectForKey:(id)aKey { + if (!aKey) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return; + } + [self guard_removeObjectForKey:aKey]; +} + +- (void)guard_setObject:(id)anObject forKey:(id )aKey { + if (!anObject) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return; + } + if (!aKey) { + [[self class] warningDeveloper:NSSelectorFromString([NSString stringWithFormat:@"%s",__FUNCTION__])]; + return; + } + [self guard_setObject:anObject forKey:aKey]; +} + ++ (void)warningDeveloper:(SEL)aSelector{ +#if DEBUG + + NSString *selectorStr = NSStringFromSelector(aSelector); + NSLog(@"PROTECTOR: -[%@ %@]", [self class], selectorStr); + NSLog(@"PROTECTOR: unrecognized selector \"%@\" sent to instance: %p", selectorStr, self); + NSLog(@"PROTECTOR: call stack: %@", [NSThread callStackSymbols]); + NSAssert(NO, @"marr调用出错---[%@-%@]", [self class], selectorStr); + // @throw @"方法找不到"; +#endif +} +@end diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSObject+Selector.h b/FXZRedoVendor/Classes/FXZYCrashHandle/NSObject+Selector.h new file mode 100644 index 0000000..f0f069a --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSObject+Selector.h @@ -0,0 +1,17 @@ +// +// NSObject+Selector.h +// strongDemo +// +// Created by sxk on 2020/8/3. +// Copyright © 2020 sxk. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSObject (Selector) + +@end + +NS_ASSUME_NONNULL_END diff --git a/FXZRedoVendor/Classes/FXZYCrashHandle/NSObject+Selector.m b/FXZRedoVendor/Classes/FXZYCrashHandle/NSObject+Selector.m new file mode 100644 index 0000000..2571d4a --- /dev/null +++ b/FXZRedoVendor/Classes/FXZYCrashHandle/NSObject+Selector.m @@ -0,0 +1,89 @@ +// +// NSObject+Selector.m +// strongDemo +// +// Created by sxk on 2020/8/3. +// Copyright © 2020 sxk. All rights reserved. +// + +#import "NSObject+Selector.h" +#import +@implementation NSObject (Selector) + ++ (void)load +{ + Method method1 = class_getInstanceMethod(self, @selector(forwardingTargetForSelector:)); + Method method2 = class_getInstanceMethod(self, @selector(sxk_forwardingTargetForSelector:)); + method_exchangeImplementations(method1, method2); +} + +- (id)sxk_forwardingTargetForSelector:(SEL)aSelector +{ + if ([self isCurrentClassInWhiteList]) { + [[self class] warningDeveloper:aSelector]; + + Class protectorCls = NSClassFromString(@"ProtectorClassName"); + if (!protectorCls){ + protectorCls = objc_allocateClassPair([NSObject class], "ProtectorClassName", 0); + objc_registerClassPair(protectorCls); + } + + if (![self isExistSelector:aSelector inClass:protectorCls]){ + //动态为一个类加载方法 使本次方法加载到ProtectorClassName上 + class_addMethod(protectorCls, aSelector, [self safeImplementation:aSelector],[NSStringFromSelector(aSelector) UTF8String]); + } + + Class Protector = [protectorCls class]; + id instance = [[Protector alloc] init]; + return instance; + } else { + return nil; + } +} + +#pragma clang diagnostic pop + +- (BOOL)isCurrentClassInWhiteList{ + NSArray *classNameArray = @[@"NSNull",@"NSString",@"NSArray",@"NSDictionary",@"NSURL"]; + for (NSString *className in classNameArray) { + if ([self isKindOfClass:NSClassFromString(className)]) { + return YES; + } + } + return NO; +} + +- (BOOL)isExistSelector:(SEL)aSelector inClass:(Class)currentClass{ + BOOL isExist = NO; + unsigned int methodCount = 0; + Method *methods = class_copyMethodList(currentClass, &methodCount); + for (int i = 0; i < methodCount; i++){ + Method temp = methods[i]; + SEL sel = method_getName(temp); + NSString *methodName = NSStringFromSelector(sel); + if ([methodName isEqualToString: NSStringFromSelector(aSelector)]){ + isExist = YES; + break; + } + } + return isExist; +} + +- (IMP)safeImplementation:(SEL)aSelector{ + IMP imp = imp_implementationWithBlock(^(){ + NSLog(@"PROTECTOR: %@ Done", NSStringFromSelector(aSelector)); + }); + return imp; +} + ++ (void)warningDeveloper:(SEL)aSelector{ +#if DEBUG + NSString *selectorStr = NSStringFromSelector(aSelector); + NSLog(@"PROTECTOR: -[%@ %@]", [self class], selectorStr); + NSLog(@"PROTECTOR: unrecognized selector \"%@\" sent to instance: %p", selectorStr, self); + NSLog(@"PROTECTOR: call stack: %@", [NSThread callStackSymbols]); + //NSAssert(NO, @"调用不存在的方法---[%@-%@]", [self class], selectorStr); + // @throw @"方法找不到"; +#endif +} +@end