乐趣区

iOS | NSProxy

Objective- C 作为一种动态消息型语言, 其机制不同于 Java ,C# 等编译型语言. 它将数据类型的确定等工作推迟到了运行时期来执行, 并且它调用方法的方式实质是像对象发送消息, 根据 selector 在对象的本类以及父类中的方法列表进行查找, 如果都找不到就会启动消息转发机制.
回到正题, 这个话题我想谈下 OC 的单继承原则.OC 确实是只能单继承的语言, 但是基于运行时的机制, 却有一种方法让它来实现一下 ” 伪多继承 ”. 就是利用 NSProxy 这个类.
NSProxy 是和 NSObject 同级的一个类, 可以说它是一个虚拟类, 它只是实现了 <NSObject> 的协议. 它的作用有点类似于一个复制类, 有人曾经笑谈它是卡卡西的复制忍术, 想想其实也挺贴切的, 其实原理确实如此.
过程: 用一个继承于 NSProxy 的子类, 在它内部实现一些方法, 暴露一个公开方法 transform, 这个方法是使它变身的关键. 然后它变身之后可以对那些对象发送消息, 并且可以在内部拦截消息的内容并修改.
可以说, 几乎可以变身成为任何对象.
直接上个代码来展示下
JanProxy.h
#import <Foundation/Foundation.h>

@interface JanProxy : NSProxy

– (void)transformObjc:(NSObject *)objc;

@end

JanProxy.m
#import “JanProxy.h”

@interface JanProxy ()

@property(nonatomic,strong)NSObject *objc;

@end

@implementation JanProxy

– (void)transformObjc:(NSObject *)objc
{
// 复制对象
self.objc = objc;
}

//2. 有了方法签名之后就会调用方法实现
– (void)forwardInvocation:(NSInvocation *)invocation
{
if (self.objc) {
// 拦截方法的执行者为复制的对象
[invocation setTarget:self.objc];

if ([self.objc isKindOfClass:[NSClassFromString(@”Cat”) class]]) {
// 拦截参数 Argument: 表示的是方法的参数 index: 表示的是方法参数的下标
NSString *str = @” 拦截消息 ”;
[invocation setArgument:&str atIndex:2];
}

// 开始调用方法
[invocation invoke];
}

}

//1. 查询该方法的方法签名
– (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
NSMethodSignature *signature = nil;
if ([self.objc methodSignatureForSelector:sel]) {
signature = [self.objc methodSignatureForSelector:sel];
}
else
{
signature = [super methodSignatureForSelector:sel];
}

return signature;
}

@end

使用方法

Dog *dog = [[Dog alloc]init];

//OC 中方法的调用本质上是给这个对象发送一个消息
Cat *cat = [[Cat alloc] init];

// 开始复制拦截方法
JanProxy *proxy = [JanProxy alloc];
// 开始变身成猫
[proxy transformObjc:cat];
// 开始调猫的方法
[proxy performSelector:@selector(eat:) withObject:@” 猫发出消息 ”];

// 开始变身成狗
[proxy transformObjc:Dog];
// 开始调用学生的方法
[proxy performSelector:@selector(shut)];
最后的结果

发现没有, 猫发出消息已经被子类的内部拦截并且做出了修改.
总结
OC 中存在这么一个默默无闻的类 NSProxy, 填补了 ” 多继承 ” 这个空白区.

退出移动版