iOS | NSProxy
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的更多相关文章
- [转]NSProxy实现AOP方便为ios应用实现异常处理策略
[转载自:http://blog.csdn.net/yanghua_kobe/article/details/8395535] 前段时间关注过objc实现的AOP,在GitHub找到了其中的两个库:A ...
- iOS 消息转发以及 NSProxy 实战
最后更新: 2018-01-17 一.消息派发机制-NSObject 在 iOS 开发中, 调用对象的方法就是给对象发送一个消息.了解消息的派发机制对于iOS开发来说是一个很实用且强大的工具, 下面我 ...
- NSProxy实现AOP方便为ios应用实现异常处理策略
前段时间关注过objc实现的AOP. 在GitHub找到了其中的两个库:AOP-in-Objective-C 和 AOP-for-Objective-C 第一个是基于NSProxy来实现的:第二个是基 ...
- iOS Class 使用NSProxy和NSObject设计代理类的差异
经常发现在一些需要使用消息转发而创建代理类时, 不同的程序员都有着不同的使用方法, 有些采用继承于NSObject, 而有一些采用继承自NSProxy. 二者都是Foundation框架中的基类, 并 ...
- iOS开发——高级特性&Runtime运行时特性详解
Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 ...
- iOS RunTime运行时(1):类与对象
Objective-C语言是一门动态语言,他将很多静态语言在编译和链接期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码更具有灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一下 ...
- iOS运行时Runtime浅析
运行时是iOS中一个很重要的概念,iOS运行过程中都会被转化为runtime的C代码执行.例如[target doSomething];会被转化成objc)msgSend(target,@select ...
- iOS经典面试题(转)
iOS经典面试题 前言 写这篇文章的目的是因为前两天同学想应聘iOS开发,从网上找了iOS面试题和答案让我帮忙看看.我扫了一眼,倒吸了一口冷气,仔细一看,气的发抖.整篇题目30多个没有一个答案是对 ...
- iOS 简单工厂模式
iOS 简单工厂模式 什么是简单工厂模式? 简单工厂模式中定义一个抽象类,抽象类中声明公共的特征及属性,抽象子类继承自抽象类,去实现具体的操作.工厂类根据外界需求,在工厂类中创建对应的抽象子类实例并传 ...
随机推荐
- csharp:Google TTS API text to speech
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- javascript实现SHA1算法
web里面密码直接传到后台是不安全的,有时候需要进行加密,找到一个不错的javascript SHA1算法: <!DOCTYPE html> <html lang="en& ...
- springboot 使用webflux响应式开发教程(一)
什么是webFlux 左侧是传统的基于Servlet的Spring Web MVC框架,右侧是5.0版本新引入的基于Reactive Streams的Spring WebFlux框架,从上到下依次是R ...
- .net CombinedGeometry的合并模式
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="h ...
- 17.分支的合并&遇到冲突时的分支合并
分支的合并 假设你已经修正了 #53 问题,并且打算将你的工作合并入 master 分支. 为此,你需要合并 iss53 分支到 master 分支,这和之前你合并 hotfix 分支所做的工作差不多 ...
- linux 用户和组操作
linux用户操作 查看登陆用户:whoami (结果最简洁) 或者who mom likes 或者who am i查看所有用户:cat /etc/passwd 添加:sudo adduser lil ...
- SQL删除多列语句的写法
SQL删除表中多个列的写法: ALTER TABLE table_name DROP COLUMN COLUMN1,COLUMN COLUMN2,COLUMN COLUMN3 ……
- 使用Python批量合并PDF文件(带书签功能)
网上找了几个合并pdf的软件,发现不是很好用,一般都没有添加书签的功能. 又去找了下python合并pdf的脚本,发现也没有添加书签的功能的. 于是自己动手编写了一个小工具,使用了PyPDF2. 下面 ...
- Python学习---线程基础学习
线程基础 什么是线程(thread) 线程是CPU调度能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流[换言之,线程就是一堆指令集合], ...
- laravel中delete()方法和destroy()方法的区别
delete()方法是实例方法,需要查询到相应的数据并通过模型实例调用 destroy()方法可以直接调用,通过索引删除记录 举个栗子: /*delete()方法删除*/ //先查找记录 $blog ...