Objective-C作为一种动态消息型语言,其机制不同于Java ,C#等编译型语言.

它将数据类型的确定等工作推迟到了运行时期来执行,并且它调用方法的方式实质是像对象发送消息,根据selector在对象的本类以及父类中的方法列表进行查找,如果都找不到就会启动消息转发机制.

回到正题,这个话题我想谈下OC的单继承原则.

OC确实是只能单继承的语言,但是基于运行时的机制,却有一种方法让它来实现一下"伪多继承".就是利用NSProxy这个类.

NSProxy是和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,填补了"多继承"这个空白区.

iOS | NSProxy的更多相关文章

  1. [转]NSProxy实现AOP方便为ios应用实现异常处理策略

    [转载自:http://blog.csdn.net/yanghua_kobe/article/details/8395535] 前段时间关注过objc实现的AOP,在GitHub找到了其中的两个库:A ...

  2. iOS 消息转发以及 NSProxy 实战

    最后更新: 2018-01-17 一.消息派发机制-NSObject 在 iOS 开发中, 调用对象的方法就是给对象发送一个消息.了解消息的派发机制对于iOS开发来说是一个很实用且强大的工具, 下面我 ...

  3. NSProxy实现AOP方便为ios应用实现异常处理策略

    前段时间关注过objc实现的AOP. 在GitHub找到了其中的两个库:AOP-in-Objective-C 和 AOP-for-Objective-C 第一个是基于NSProxy来实现的:第二个是基 ...

  4. iOS Class 使用NSProxy和NSObject设计代理类的差异

    经常发现在一些需要使用消息转发而创建代理类时, 不同的程序员都有着不同的使用方法, 有些采用继承于NSObject, 而有一些采用继承自NSProxy. 二者都是Foundation框架中的基类, 并 ...

  5. iOS开发——高级特性&Runtime运行时特性详解

    Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 ...

  6. iOS RunTime运行时(1):类与对象

    Objective-C语言是一门动态语言,他将很多静态语言在编译和链接期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码更具有灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一下 ...

  7. iOS运行时Runtime浅析

    运行时是iOS中一个很重要的概念,iOS运行过程中都会被转化为runtime的C代码执行.例如[target doSomething];会被转化成objc)msgSend(target,@select ...

  8. iOS经典面试题(转)

    iOS经典面试题   前言 写这篇文章的目的是因为前两天同学想应聘iOS开发,从网上找了iOS面试题和答案让我帮忙看看.我扫了一眼,倒吸了一口冷气,仔细一看,气的发抖.整篇题目30多个没有一个答案是对 ...

  9. iOS 简单工厂模式

    iOS 简单工厂模式 什么是简单工厂模式? 简单工厂模式中定义一个抽象类,抽象类中声明公共的特征及属性,抽象子类继承自抽象类,去实现具体的操作.工厂类根据外界需求,在工厂类中创建对应的抽象子类实例并传 ...

随机推荐

  1. jquery文本框textarea自适应高度

    浏览器中默认的文本框是不能根据内容的增多变高,只能固定高度有滚动条,体验不是很好,找了很多方法兼容都不行,总算找到个兼容良好的方法: <body> <textarea id=&quo ...

  2. BZOJ4698: Sdoi2008 Sandy的卡片(后缀数组 二分)

    题意 题目链接 Sol 不要问我为什么发两篇blog,就是为了骗访问量 后缀数组的也比较好想,先把所有位置差分,然后在height数组中二分就行了 数据好水啊 // luogu-judger-enab ...

  3. USG防火墙基础

    http://support.huawei.com/huaweiconnect/enterprise/thread-331003.html 华为防火墙产品线 安全区域 1.     默认防火墙区域 T ...

  4. TextView的跑马灯效果(AS开发实战第二章学习笔记)

    TextView的跑马灯效果跑马灯用到的属性与方法说明singleLine 指定文本是否单行显示ellipsize 指定文本超出范围后的省略方式focusable 指定是否获得焦点,跑马灯效果要求设置 ...

  5. 树莓派搭建web服务器(详细且良心)

    安装Apache Apache服务器可以从Debian的源中下载.可以用apt下载. 首先要更新apt的软件列表.如果不运行sudo apt-get updata的话,apt软件就不知道有没有新的软件 ...

  6. ES入门——数组的扩展

    1.Array.from() 该方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象,包括ES6新增的数据结构Set和Map.下面是 ...

  7. qt 样式表基本用法

    Qt样式表 QT样式表参考CSS层叠样式表设计,不同之处在于QT样式表应用于Widget世界. 可以使用QApplication::setStyleSheet()函数设置到整个应用程序上,也可以使用Q ...

  8. Linux->ZooKeeper开机启动的俩种方式

    两种方式可以实现开机自启动 第一种:直接修改/etc/rc.d/rc.local文件 在/etc/rc.d/rc.local文件中需要输入两行, 其中export JAVA_HOME=/usr/jav ...

  9. wcf 访问控制

    public class PasswordDigestChannelFactory<TPortTypeClient, TPlugin> where TPortTypeClient : Cl ...

  10. IERS-OSPF基本工作原理

    IERS-OSPF基本工作原理 一.邻居建立建立过程 1.Router ID 用于在自治系统中唯一标识一台运行OSPF的路由器,每台运行OSPF的路由器都有一个ROUTER ID Route ID 是 ...