Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
xcuserdata
xcshareddata
DerivedData/
52 changes: 45 additions & 7 deletions NSObjectSafe/NSObjectSafe.m
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ + (void)load
swizzleInstanceMethod([NSObject class], @selector(removeObserver:forKeyPath:), @selector(hookRemoveObserver:forKeyPath:));
swizzleInstanceMethod([NSObject class], @selector(methodSignatureForSelector:), @selector(hookMethodSignatureForSelector:));
swizzleInstanceMethod([NSObject class], @selector(forwardInvocation:), @selector(hookForwardInvocation:));
[NSObject swizzleClassMethod:@selector(methodSignatureForSelector:) withMethod:@selector(hookMethodSignatureForSelector:)];
[NSObject swizzleClassMethod:@selector(forwardInvocation:) withMethod:@selector(hookForwardInvocation:)];
});
}
- (void) hookAddObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
Expand Down Expand Up @@ -168,6 +170,22 @@ - (void) hookRemoveObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath
}
}

+ (NSMethodSignature*)hookMethodSignatureForSelector:(SEL)aSelector {
NSMethodSignature* sig = [self hookMethodSignatureForSelector:aSelector];
if (sig) {
return sig;
}

return [self.class checkObjectSignatureAndCurrentClass:self.class];
}

+ (void)hookForwardInvocation:(NSInvocation*)invocation
{
NSString* info = [NSString stringWithFormat:@"unrecognized static selector [%@] sent to %@", NSStringFromSelector(invocation.selector), NSStringFromClass(self.class)];
[[NSNotificationCenter defaultCenter] postNotificationName:NSSafeNotification object:self userInfo:@{@"invocation":invocation}];
[[[NSSafeProxy new] autorelease] dealException:info];
}

- (NSMethodSignature*)hookMethodSignatureForSelector:(SEL)aSelector {
/* 如果 当前类有methodSignatureForSelector实现,NSObject的实现直接返回nil
* 子类实现如下:
Expand All @@ -179,14 +197,10 @@ - (NSMethodSignature*)hookMethodSignatureForSelector:(SEL)aSelector {
* return sig;
*/
NSMethodSignature* sig = [self hookMethodSignatureForSelector:aSelector];
if (!sig){
if (class_getMethodImplementation([NSObject class], @selector(methodSignatureForSelector:))
!= class_getMethodImplementation(self.class, @selector(methodSignatureForSelector:)) ){
return nil;
}
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
if (sig) {
return sig;
}
return sig;
return [self.class checkObjectSignatureAndCurrentClass:self.class];
}

- (void)hookForwardInvocation:(NSInvocation*)invocation
Expand All @@ -196,6 +210,28 @@ - (void)hookForwardInvocation:(NSInvocation*)invocation
[[[NSSafeProxy new] autorelease] dealException:info];
}

/**
* Check the class method signature to the [NSObject class]
* If not equals,return nil
* If equals,return the v@:@ method

@param currentClass Class
@return NSMethodSignature
*/
+ (NSMethodSignature *)checkObjectSignatureAndCurrentClass:(Class)currentClass {
IMP originIMP = class_getMethodImplementation([NSObject class], @selector(methodSignatureForSelector:));
IMP currentClassIMP = class_getMethodImplementation(currentClass, @selector(methodSignatureForSelector:));

// If current class override methodSignatureForSelector return nil
if (originIMP != currentClassIMP){
return nil;
}

// Customer method signature
// void xxx(id,sel,id)
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}

@end

#pragma mark - NSString
Expand Down Expand Up @@ -1066,6 +1102,8 @@ + (instancetype) hookDictionaryWithObjects:(const id [])objects forKeys:(const i
ks[index] = keys[i];
objs[index] = objects[i];
++index;
} else {
SFAssert(NO, @"NSDictionary invalid args hookDictionaryWithObject:[%@] forKey:[%@]", objects, keys);
}
}
return [self hookDictionaryWithObjects:objs forKeys:ks count:index];
Expand Down
2 changes: 2 additions & 0 deletions NSObjectSafeTests/NSObjectSafeTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ - (void)testExample {

NSArray* array = @"hello";
NSLog(@"%@", [array objectAtIndex:1]);

NSLog(@"%@", [NSArray performSelector:NSSelectorFromString(@"hello")]);

array = [NSArray arrayWithObjects:@1, @2, nil];//__NSArrayI
[array subarrayWithRange:NSMakeRange(0, 1)];
Expand Down