-
Notifications
You must be signed in to change notification settings - Fork 269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
添加了对KVC崩溃的Hook #53
base: master
Are you sure you want to change the base?
添加了对KVC崩溃的Hook #53
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// | ||
// JJPerson.h | ||
// JJException | ||
// | ||
// Created by 无头骑士 GJ on 2019/1/30. | ||
// Copyright © 2019 Jezz. All rights reserved. | ||
// | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
@interface JJPerson : NSObject | ||
{ | ||
int age; | ||
} | ||
|
||
|
||
@property (nonatomic, strong) NSString *name; | ||
|
||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// | ||
// JJPerson.m | ||
// JJException | ||
// | ||
// Created by 无头骑士 GJ on 2019/1/30. | ||
// Copyright © 2019 Jezz. All rights reserved. | ||
// | ||
|
||
#import "JJPerson.h" | ||
|
||
@implementation JJPerson | ||
+ (BOOL)accessInstanceVariablesDirectly | ||
{ | ||
return YES; | ||
} | ||
@end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// | ||
// NSObject+KVCCrash.h | ||
// JJException | ||
// | ||
// Created by 无头骑士 GJ on 2019/1/30. | ||
// Copyright © 2019 Jezz. All rights reserved. | ||
// | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
@interface NSObject (KVCCrash) | ||
+ (void)jj_swizzleKVCCrash; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 函数上下各空一行 |
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// | ||
// NSObject+KVCCrash.m | ||
// JJException | ||
// | ||
// Created by 无头骑士 GJ on 2019/1/30. | ||
// Copyright © 2019 Jezz. All rights reserved. | ||
// | ||
|
||
#import "NSObject+KVCCrash.h" | ||
#import "NSObject+SwizzleHook.h" | ||
#import "JJExceptionProxy.h" | ||
#import <objc/message.h> | ||
|
||
@implementation NSObject (KVCCrash) | ||
+ (void)jj_swizzleKVCCrash | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 大括号问题 |
||
swizzleInstanceMethod([self class], @selector(setValue:forKey:), @selector(hookSetValue:forKey:)); | ||
} | ||
|
||
- (void)hookSetValue:(id)value forKey:(NSString *)key | ||
{ | ||
if (key.length == 0) return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if (key.length == 0) { |
||
|
||
|
||
NSString *methodSuffix = [NSString stringWithFormat: @"%@%@", [[key substringToIndex: 1] uppercaseString], [key substringFromIndex: 1]]; | ||
|
||
// 1、判断setKey方法是否存在 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 注释最好用英文 |
||
SEL setXXSelector = NSSelectorFromString([NSString stringWithFormat: @"set%@", methodSuffix]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 建议不要用XX这种命名,明确变量的含义 |
||
Method setXXMethod = class_getInstanceMethod([self class], setXXSelector); | ||
|
||
if (setXXMethod) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 大括号问题 |
||
[self hookSetValue: value forKey: key]; | ||
return; | ||
} | ||
|
||
// 2、判断_setKey方法是否存在 | ||
SEL _setXXSelector = NSSelectorFromString([NSString stringWithFormat: @"_set%@", methodSuffix]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 不要XX这种命名,明确变量的意思 |
||
Method _setXXMethod = class_getInstanceMethod([self class], _setXXSelector); | ||
if (_setXXMethod) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 大括号问题 |
||
{ | ||
[self hookSetValue: value forKey: key]; | ||
return; | ||
} | ||
|
||
// 3、accessInstanceVariablesDirectly的返回值,如果为NO,直接抛出异常 | ||
SEL accessInstanceVariablesDirectlySEL = @selector(accessInstanceVariablesDirectly); | ||
NSMethodSignature *methodSignature = [NSMethodSignature methodSignatureForSelector: accessInstanceVariablesDirectlySEL]; | ||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: methodSignature]; | ||
[invocation setSelector: accessInstanceVariablesDirectlySEL]; | ||
[invocation invokeWithTarget: [self class]]; | ||
|
||
BOOL result; | ||
[invocation getReturnValue: &result]; | ||
|
||
// 异常处理 | ||
if (result == NO) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 布尔类型不需要==,直接if (result)这种就行,还有括号问题 |
||
{ | ||
handleCrashException(JJExceptionGuardKVCCrash, @"hookSetValue:forKey: key is not exist"); | ||
return; | ||
} | ||
|
||
// 4、检查是否存在 _key、_isKey、key, isKey任一属性是否包含在成员变量中 | ||
NSMutableArray *keys = [NSMutableArray array]; | ||
[keys addObject: [NSString stringWithFormat: @"_%@", key]]; | ||
[keys addObject: [NSString stringWithFormat: @"_is%@", methodSuffix]]; | ||
[keys addObject: [NSString stringWithFormat: @"%@", key]]; | ||
[keys addObject: [NSString stringWithFormat: @"is%@", methodSuffix]]; | ||
|
||
unsigned int count = 0; | ||
Ivar *members = class_copyIvarList([self class], &count); | ||
|
||
__block BOOL find = NO; | ||
for (int i = 0; i < count; i++) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 第一个括号不需要换行 |
||
Ivar var = members[i]; | ||
NSString *memeberName = [[NSString alloc] initWithUTF8String: ivar_getName(var)]; | ||
|
||
if (![[memeberName lowercaseString] containsString: key]) continue; | ||
|
||
[keys enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { | ||
|
||
if ([obj isEqualToString: memeberName]) | ||
{ | ||
find = YES; | ||
[self hookSetValue: value forKey: key]; | ||
*stop = YES; | ||
} | ||
}]; | ||
|
||
if (find) break; | ||
|
||
} | ||
|
||
if (find == NO) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 布尔类型和括号问题 |
||
handleCrashException(JJExceptionGuardKVCCrash, @"hookSetValue:forKey: key is not exist"); | ||
} | ||
|
||
|
||
@end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,8 +35,9 @@ typedef NS_OPTIONS(NSInteger,JJExceptionGuardCategory){ | |
JJExceptionGuardNSTimer = 1 << 6, | ||
JJExceptionGuardNSNotificationCenter = 1 << 7, | ||
JJExceptionGuardNSStringContainer = 1 << 8, | ||
JJExceptionGuardKVCCrash = 1 << 9, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 麻烦写下这个枚举的注释,用英文 |
||
JJExceptionGuardAllExceptZombie = JJExceptionGuardUnrecognizedSelector | JJExceptionGuardDictionaryContainer | JJExceptionGuardArrayContainer | JJExceptionGuardKVOCrash | JJExceptionGuardNSTimer | JJExceptionGuardNSNotificationCenter | JJExceptionGuardNSStringContainer, | ||
JJExceptionGuardAll = JJExceptionGuardUnrecognizedSelector | JJExceptionGuardDictionaryContainer | JJExceptionGuardArrayContainer | JJExceptionGuardZombie | JJExceptionGuardKVOCrash | JJExceptionGuardNSTimer | JJExceptionGuardNSNotificationCenter | JJExceptionGuardNSStringContainer, | ||
JJExceptionGuardAll = JJExceptionGuardUnrecognizedSelector | JJExceptionGuardDictionaryContainer | JJExceptionGuardArrayContainer | JJExceptionGuardZombie | JJExceptionGuardKVOCrash | JJExceptionGuardNSTimer | JJExceptionGuardNSNotificationCenter | JJExceptionGuardNSStringContainer | JJExceptionGuardKVCCrash, | ||
}; | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -177,6 +177,11 @@ - (void)setIsProtectException:(BOOL)isProtectException{ | |
[NSAttributedString performSelector:@selector(jj_swizzleNSAttributedString)]; | ||
[NSMutableAttributedString performSelector:@selector(jj_swizzleNSMutableAttributedString)]; | ||
} | ||
|
||
if (self.exceptionGuardCategory & JJExceptionGuardKVCCrash) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 括号不需要换行 |
||
{ | ||
[NSObject performSelector: @selector(jj_swizzleKVCCrash)]; | ||
} | ||
#pragma clang diagnostic pop | ||
} | ||
dispatch_semaphore_signal(_swizzleLock); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
#import "ViewController.h" | ||
#import "JJException.h" | ||
#import <objc/runtime.h> | ||
#import "JJPerson.h" | ||
#import "PushViewController.h" | ||
|
||
@interface ViewController ()<JJExceptionHandle> | ||
|
@@ -48,6 +49,13 @@ - (void)viewDidLoad { | |
otherButton.frame = CGRectMake(0, 350, self.view.frame.size.width, 50); | ||
[otherButton addTarget:self action:@selector(testArrayDictionaryUnrecognizedSelector) forControlEvents:UIControlEventTouchUpInside]; | ||
[self.view addSubview:otherButton]; | ||
|
||
UIButton* kvcButton = [UIButton buttonWithType:UIButtonTypeSystem]; | ||
[kvcButton setTitle:@"Test KVC" forState:UIControlStateNormal]; | ||
[kvcButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; | ||
kvcButton.frame = CGRectMake(0, 450, self.view.frame.size.width, 50); | ||
[kvcButton addTarget:self action:@selector(keyButtonClick) forControlEvents:UIControlEventTouchUpInside]; | ||
[self.view addSubview:kvcButton]; | ||
} | ||
#pragma mark - Exception Delegate | ||
|
||
|
@@ -106,4 +114,12 @@ - (void)testNull{ | |
NSLog(@"Str length:%ld",str.length); | ||
} | ||
|
||
- (void)keyButtonClick | ||
{ | ||
JJPerson *p = [JJPerson new]; | ||
[p setValue: @"123" forKeyPath: @"age"]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 没开启保护时,也不会闪退,你应该测试异常和正常情况 |
||
|
||
NSLog(@"%@", [p valueForKey: @"age"]); | ||
} | ||
|
||
@end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
函数上下各空一行,大括号紧跟在函数名且空一个空格