文章40 | 阅读 19061 | 点赞0
NS_ROOT_CLASS
@interface NSProxy <NSObject> {
Class isa;
}
+ (id)alloc;
+ (id)allocWithZone:(nullable NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ (Class)class;
- (void)forwardInvocation:(NSInvocation *)invocation;
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel NS_SWIFT_UNAVAILABLE("NSInvocation and related APIs not available");
- (void)dealloc;
- (void)finalize;
@property (readonly, copy) NSString *description;
@property (readonly, copy) NSString *debugDescription;
+ (BOOL)respondsToSelector:(SEL)aSelector;
- (BOOL)allowsWeakReference API_UNAVAILABLE(macos, ios, watchos, tvos);
- (BOOL)retainWeakReference API_UNAVAILABLE(macos, ios, watchos, tvos);
// - (id)forwardingTargetForSelector:(SEL)aSelector;
Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object. Subclasses of NSProxy can be used to implement transparent distributed messaging (for example, NSDistantObject) or for lazy instantiation of objects that are expensive to create.
NSProxy implements the basic methods required of a root class, including those defined in the NSObject protocol. However, as an abstract class it doesn’t provide an initialization method, and it raises an exception upon receiving any message it doesn’t respond to. A concrete subclass must therefore provide an initialization or creation method and override the forwardInvocation: and methodSignatureForSelector: methods to handle messages that it doesn’t implement itself. A subclass’s implementation of forwardInvocation: should do whatever is needed to process the invocation, such as forwarding the invocation over the network or loading the real object and passing it the invocation. methodSignatureForSelector: is required to provide argument type information for a given message; a subclass’s implementation should be able to determine the argument types for the messages it needs to forward and should construct an NSMethodSignature object accordingly. See the NSDistantObject, NSInvocation, and NSMethodSignature class specifications for more information.
@implementation classA
- (void)infoA {
NSLog(@"classA");
}
@end
@implementation classB
- (void)infoB {
NSLog(@"classB");
}
@end
@interface ClassProxy : NSProxy
@property(nonatomic, strong, readonly) NSMutableArray *targetArray;
- (void)target:(id)target;
- (void)handleTargets:(NSArray *)targets;
@end
@interface ClassProxy()
@property (nonatomic, strong) NSMutableArray *targetArray; // 多个 targets 皆可代理
@property (nonatomic, strong) NSMutableDictionary *methodDic;
@property (nonatomic, strong) id target;
@end
- (void)registMethodWithTarget:(id)target {
unsigned int countOfMethods = 0;
Method *method_list = class_copyMethodList([target class], &countOfMethods);
for (int i = 0; i < countOfMethods; i++) {
Method method = method_list[i];
// 得到方法的符号
SEL sel = method_getName(method);
// 得到方法的符号字符串
const char *sel_name = sel_getName(sel);
// 得到方法的名字
NSString *method_name = [NSString stringWithUTF8String:sel_name];
self.methodDic[method_name] = target;
}
free(method_list);
}
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL sel = invocation.selector;
NSString *methodName = NSStringFromSelector(sel);
id target = self.methodDic[methodName];
if (target) {
[invocation invokeWithTarget:target];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
NSMethodSignature *Method;
NSString *methodName = NSStringFromSelector(sel);
id target = self.methodDic[methodName];
if (target) {
Method = [target methodSignatureForSelector:sel];
} else {
Method = [super methodSignatureForSelector:sel];
}
return Method;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self classInheritance];
}
/**
* 多继承
*/
- (void)classInheritance {
classA *A = [[classA alloc] init];
classB *B = [[classB alloc] init];
ClassProxy *proxy = [ClassProxy alloc];
[proxy handleTargets:@[A, B]];
[proxy performSelector:@selector(infoA)];
[proxy performSelector:@selector(infoB)];
}
// 运行结果
classA
classB
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer timerWithTimeInterval:1
target:[WeakProxy proxyWithTarget:self]
selector:@selector(invoked:)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
- (void)invoked:(NSTimer *)timer {
NSLog(@"1");
}
@interface WeakProxy ()
@property (nonatomic, weak) id target;
@end
@implementation WeakProxy
+ (instancetype)proxyWithTarget:(id)target {
return [[self alloc] initWithTarget:target];
}
- (instancetype)initWithTarget:(id)target {
self.target = target;
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL sel = invocation.selector;
if ([self.target respondsToSelector:sel]) {
[invocation invokeWithTarget:self.target];
}
}
@end
/**
* 参数 1:接受消息的 target
* 参数 2:要执行的 selector
* 参数 3:要调用的方法
* 可变参数:若干个要传给 selector 的参数
*/
id objc_msgSend(id self, SEL _cmd, ...)
@interface MyProxy : NSProxy {
id _innerObject; // 在内部持有要 hook 的对象
}
+ (instancetype)proxyWithObj:(id)object;
@end
@interface Dog : NSObject
- (NSString *)barking:(NSInteger)months;
@end
@implementation MyProxy
+ (instancetype)proxyWithObj:(id)object {
MyProxy * proxy = [MyProxy alloc];
// 持有要 hook 的对象
proxy->_innerObject = object;
// 注意返回 Proxy 对象
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
// 可以返回任何 NSMethodSignature 对象,也可以完全自己构造
return [_innerObject methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
if([_innerObject respondsToSelector:invocation.selector]){
NSString *selectorName = NSStringFromSelector(invocation.selector);
NSLog(@"Before calling %@",selectorName);
[invocation retainArguments];
NSMethodSignature *sig = [invocation methodSignature];
// 获取参数个数,本例这里值是 3,因为 objc_msgSend 隐含了 self、selector 参数
NSUInteger cnt = [sig numberOfArguments];
// 将简单的将参数和返回值打印出来
for (int i = 0; i < cnt; i++) {
// 参数类型
const char * type = [sig getArgumentTypeAtIndex:i];
if(strcmp(type, "@") == 0){
NSObject *obj;
[invocation getArgument:&obj atIndex:i];
// 这里输出的是:"parameter (0)'class is MyProxy",也证明了这是 objc_msgSend 的第一个参数
NSLog(@"parameter (%d)'class is %@", i, [obj class]);
} else if(strcmp(type, ":") == 0){
SEL sel;
[invocation getArgument:&sel atIndex:i];
// 这里输出的是:"parameter (1) is barking:",也就是 objc_msgSend 的第二个参数
NSLog(@"parameter (%d) is %@", i, NSStringFromSelector(sel));
} else if(strcmp(type, "q") == 0){
int arg = 0;
[invocation getArgument:&arg atIndex:i];
// 输出的是:"parameter (2) is int value is 4",稍后会看到在调用 barking 的时候传递的参数就是 4
NSLog(@"parameter (%d) is int value is %d", i, arg);
}
}
// 消息转发
[invocation invokeWithTarget:_innerObject];
const char *retType = [sig methodReturnType];
if(strcmp(retType, "@") == 0){
NSObject *ret;
[invocation getReturnValue:&ret];
// 输出的是:"return value is wang!"
NSLog(@"return value is %@", ret);
}
NSLog(@"After calling %@", selectorName);
}
}
@end
@implementation Dog
- (NSString *)barking:(NSInteger)months {
return months > 3 ? @"wang!" : @"Oh!";
}
@end
Dog *dog = [MyProxy proxyWithObj:[Dog alloc]];
[dog barking:4];
typedef void(^proxyBlock)(id target,SEL selector);
NS_ASSUME_NONNULL_BEGIN
@interface AOPProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
- (void)inspectSelector:(SEL)selector preSelTask:(proxyBlock)preTask endSelTask:(proxyBlock)endTask;
@end
@interface AOPProxy ()
@property (nonatomic, strong) id target;
@property (nonatomic, strong) NSMutableDictionary *preSelTaskDic;
@property (nonatomic, strong) NSMutableDictionary *endSelTaskDic;
@end
- (void)inspect {
NSMutableArray *targtArray = [AOPProxy proxyWithTarget:[NSMutableArray arrayWithCapacity:1]];
[(AOPProxy *)targtArray inspectSelector:@selector(addObject:) preSelTask:^(id target, SEL selector) {
[target addObject:@"Begin"];
NSLog(@"%@ 加进来之前", target);
} endSelTask:^(id target, SEL selector) {
[target addObject:@"End"];
NSLog(@"%@ 加进来之后", target);
}];
[targtArray addObject:@"第一个元素"];
}
( "Begin" ) 加进来之前
( "Begin",
"U662f\U4e00\U4e2a\U5143\U7d20",
"End" )
加进来之后
SomeClass *object = [SomeClass lazy];
// other thing ...
[object doSomething]; // 在这里 object 才会调用初始化方法,然后调用 doSomething
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/Forever_wj/article/details/121878461
内容来源于网络,如有侵权,请联系作者删除!