增加了 崩溃插件
parent
a28e93ae76
commit
a7a826d456
@ -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 <Foundation/Foundation.h>
|
||||
|
||||
@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
|
@ -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 <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#else
|
||||
#import <objc/objc-class.h>
|
||||
#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
|
@ -0,0 +1,16 @@
|
||||
//
|
||||
// NSArray+GHLCrashGuard.h
|
||||
// GHLCrashGuard
|
||||
//
|
||||
// Created by 与佳期 on 2019/7/11.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSArray (GHLCrashGuard)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -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
|
@ -0,0 +1,16 @@
|
||||
//
|
||||
// NSDictionary+GHLCrashGuard.h
|
||||
// GHLCrashGuard
|
||||
//
|
||||
// Created by 与佳期 on 2019/7/11.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSDictionary (GHLCrashGuard)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -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<NSCopying> *)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
|
@ -0,0 +1,16 @@
|
||||
//
|
||||
// NSMutableArray+GHLCrashGuard.h
|
||||
// GHLCrashGuard
|
||||
//
|
||||
// Created by 与佳期 on 2019/7/11.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSMutableArray (GHLCrashGuard)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -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
|
@ -0,0 +1,16 @@
|
||||
//
|
||||
// NSMutableDictionary+GHLCrashGuard.h
|
||||
// GHLCrashGuard
|
||||
//
|
||||
// Created by 与佳期 on 2019/7/11.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSMutableDictionary (GHLCrashGuard)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -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 <NSCopying>)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
|
@ -0,0 +1,17 @@
|
||||
//
|
||||
// NSObject+Selector.h
|
||||
// strongDemo
|
||||
//
|
||||
// Created by sxk on 2020/8/3.
|
||||
// Copyright © 2020 sxk. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (Selector)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -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 <objc/runtime.h>
|
||||
@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
|
Loading…
Reference in New Issue