使用NSProxy实现消息转发机制,模拟多重继承
2016-06-02 09:59
459 查看
使用NSProxy实现消息转发机制,模拟多重继承
Objective-C不支持多重继承,但是我们可以使用NSProxy的消息转发机制,来转发可由其它类的对象处理的任务,达成同样的目的。Xcode的Documentation中有示例(搜索ForwardInvocation,在SampleCode类别中),如下:
/* |
File:main.m |
Abstract:ThisexampleshowshowtodoObjectiveCmessageforwardinginFoundation. |
Version:1.0 |
Disclaimer:IMPORTANT:ThisApplesoftwareissuppliedtoyoubyApple |
Inc.("Apple")inconsiderationofyouragreementtothefollowing |
terms,andyouruse,installation,modificationorredistributionof |
thisApplesoftwareconstitutesacceptanceoftheseterms.Ifyoudo |
notagreewiththeseterms,pleasedonotuse,install,modifyor |
redistributethisApplesoftware. |
Inconsiderationofyouragreementtoabidebythefollowingterms,and |
subjecttotheseterms,Applegrantsyouapersonal,non-exclusive |
license,underApple'scopyrightsinthisoriginalApplesoftware(the |
"AppleSoftware"),touse,reproduce,modifyandredistributetheApple |
Software,withorwithoutmodifications,insourceand/orbinaryforms; |
providedthatifyouredistributetheAppleSoftwareinitsentiretyand |
withoutmodifications,youmustretainthisnoticeandthefollowing |
textanddisclaimersinallsuchredistributionsoftheAppleSoftware. |
Neitherthename,trademarks,servicemarksorlogosofAppleInc.may |
beusedtoendorseorpromoteproductsderivedfromtheAppleSoftware |
withoutspecificpriorwrittenpermissionfromApple.Exceptas |
expresslystatedinthisnotice,nootherrightsorlicenses,expressor |
implied,aregrantedbyAppleherein,includingbutnotlimitedtoany |
patentrightsthatmaybeinfringedbyyourderivativeworksorbyother |
worksinwhichtheAppleSoftwaremaybeincorporated. |
TheAppleSoftwareisprovidedbyAppleonan"ASIS"basis.APPLE |
MAKESNOWARRANTIES,EXPRESSORIMPLIED,INCLUDINGWITHOUTLIMITATION |
THEIMPLIEDWARRANTIESOFNON-INFRINGEMENT,MERCHANTABILITYANDFITNESS |
FORAPARTICULARPURPOSE,REGARDINGTHEAPPLESOFTWAREORITSUSEAND |
OPERATIONALONEORINCOMBINATIONWITHYOURPRODUCTS. |
INNOEVENTSHALLAPPLEBELIABLEFORANYSPECIAL,INDIRECT,INCIDENTAL |
ORCONSEQUENTIALDAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOF |
SUBSTITUTEGOODSORSERVICES;LOSSOFUSE,DATA,ORPROFITS;ORBUSINESS |
INTERRUPTION)ARISINGINANYWAYOUTOFTHEUSE,REPRODUCTION, |
MODIFICATIONAND/ORDISTRIBUTIONOFTHEAPPLESOFTWARE,HOWEVERCAUSED |
ANDWHETHERUNDERTHEORYOFCONTRACT,TORT(INCLUDINGNEGLIGENCE), |
STRICTLIABILITYOROTHERWISE,EVENIFAPPLEHASBEENADVISEDOFTHE |
POSSIBILITYOFSUCHDAMAGE. |
Copyright(C)2009AppleInc.AllRightsReserved. |
*/ |
#import<Foundation/Foundation.h> |
#include<stdio.h> |
@interfaceTargetProxy:NSProxy{ |
idrealObject1; |
idrealObject2; |
} |
-(id)initWithTarget1:(id)t1target2:(id)t2; |
@end |
intmain(intargc,constchar*argv[]){ |
NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init]; |
//Createanemptymutablestring,whichwillbeoneofthe |
//realobjectsfortheproxy. |
NSMutableString*string=[[NSMutableStringalloc]init]; |
//Createanemptymutablearray,whichwillbetheother |
//realobjectfortheproxy. |
NSMutableArray*array=[[NSMutableArrayalloc]init]; |
//Createaproxytowraptherealobjects.Thisisrather |
//artificialforthepurposesofthisexample--you'drarely |
//haveasingleproxycoveringtwoobjects.Butitispossible. |
idproxy=[[TargetProxyalloc]initWithTarget1:stringtarget2:array]; |
//Notethatwecan'tuseappendFormat:,becausevarargmethods |
//cannotbeforwarded! |
[proxyappendString:@"This"]; |
[proxyappendString:@"is"]; |
[proxyaddObject:string]; |
[proxyappendString:@"a"]; |
[proxyappendString:@"test!"]; |
NSLog(@"countshouldbe1,itis:%d",[proxycount]); |
if([[proxyobjectAtIndex:0]isEqualToString:@"Thisisatest!"]){ |
NSLog(@"Appendingsuccessful.",proxy); |
}else{ |
NSLog(@"Appendingfailed,got:'%@'",proxy); |
} |
NSLog(@"Examplefinishedwithouterrors."); |
[poolrelease]; |
return0; |
} |
@implementationTargetProxy |
-(id)initWithTarget1:(id)t1target2:(id)t2{ |
realObject1=[t1retain]; |
realObject2=[t2retain]; |
returnself; |
} |
-(void)dealloc{ |
[realObject1release]; |
[realObject2release]; |
[superdealloc]; |
} |
//Thecompilerknowsthetypesatthecallsitebutunfortunatelydoesn't |
//leavethemaroundforustouse,sowemustpokearoundandfindthetypes |
//sothattheinvocationcanbeinitializedfromthestackframe. |
//Here,weaskthetworealobjects,realObject1first,fortheirmethod |
//signatures,sincewe'llbeforwardingthemessagetooneortheother |
//ofthemin-forwardInvocation:.IfrealObject1returnsanon-nil |
//methodsignature,weusethat,soineffectithaspriority. |
-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{ |
NSMethodSignature*sig; |
sig=[realObject1methodSignatureForSelector:aSelector]; |
if(sig)returnsig; |
sig=[realObject2methodSignatureForSelector:aSelector]; |
returnsig; |
} |
//Invoketheinvocationonwhicheverrealobjecthadasignatureforit. |
-(void)forwardInvocation:(NSInvocation*)invocation{ |
idtarget=[realObject1methodSignatureForSelector:[invocationselector]]?realObject1:realObject2; |
[invocationinvokeWithTarget:target]; |
} |
//OverridesomeofNSProxy'simplementationstoforwardthem... |
-(BOOL)respondsToSelector:(SEL)aSelector{ |
if([realObject1respondsToSelector:aSelector])returnYES; |
if([realObject2respondsToSelector:aSelector])returnYES; |
returnNO; |
} |
@end |
使用NSProxy实现代理模式
//MyProxy.h#import<Foundation/Foundation.h>
@interfaceMyProxy:NSProxy{
NSObject*object;
}
-(id)transformToObject:(NSObject*)anObject;
@end
//MyProxy.m
#import"MyProxy.h"
@implementationMyProxy
-(void)dealloc
{
[objectrelease];
object=nil;
[superdealloc];
}
-(void)fun
{
//Dosometingvirtual
//先做一些代理工作,然后创建一个后台线程,在后台线程中再调用真正的[objectfun];
}
//Stupidtransformimplementationjustbyassigningapassedinobjectastransformationtarget.Youcanwriteyourfactoryhereandusepassedinobjectasidforobjectthatneed
otbecreated.
-(id)transformToObject:(NSObject*)anObject
{
if(object!=anObject){
[objectrelease];
}
object=[anObjectretain];
returnobject;
}
-(void)forwardInvocation:(NSInvocation*)invocation
{
if(object!=
nil){
[invocation
setTarget:object];
[invocation
invoke];
}
}
-(NSMethodSignature*)methodSignatureForSelector:(SEL)sel
{
NSMethodSignature*result;
if(object!=
nil){
result=[objectmethodSignatureForSelector:sel];
}
else{
//Willthrowanexceptionasdefaultimplementation
result=[supermethodSignatureForSelector:sel];
}
returnresult;
}
@end
//RealSubject.h
#import<Foundation/Foundation.h>
@implementationRealSubject:NSObject
-(void)fun;
@end
//RealSubject.m
#import"RealSubject.h"
@implementationRealSubject
-(void)fun
{
//这个方法需要代理进行惰性调用
//Dosomethingreal
}
-(void)otherFun
{
//这个方法不需要代理做任何处理,可直接被调用
//Dosomethingreal
}
@end
//main.m
intmain(intargc,char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];
MyProxy*myProxy=[MyProxy
alloc];
RealSubject*realSub=[[RealSubject
alloc]init];
[myProxytransformToObject:realSub];
[myProxyfun];//
直接调用myProxy的fun,执行代理工作
[myProxyotherFun];//
依次调用myProxy的methodSignatureForSelector和forwardInvocation转发给realSub,realSub调用otherFun
[realSubject
release];
[myProxyrelease];
[pool
release];
return0;
}
注意,调用MyProxy中未定义的方法otherFun会出现'MyProxy'maynotrespondto'fun'的警告,可通过使用私有范畴或通过performSelector:withObject:来避免,如果有更好的方法,请告知。
相关文章推荐
- Unable to determine if the owner (Domain\UserName) of job JOB_NAME has server access
- 用erlang写的kmp算法
- 如何在模型中融合内容信息
- 时间选择器和日期选择器 对话框 TimePickerDialog DatePickerDialog
- WebKit的JS Binding解析
- 从Solrj4到Solrj5的升级之路
- Android基础知识整合篇——ContentProvider知识点
- android_app开发集成mob短信验证码功能
- 浅谈CSRF攻击方式
- EF 更新 删除
- 动态添加菜单<ul>
- 移动端开发框架
- linq 小记
- bash: ./t.sh:/bin/bash^M:损坏的解释器: 没有那个文件或目录
- Android实现简易浏览器遇到问题的解决方法
- autorelease 什么时候释放
- CAS实现SSO单点登录原理
- 把网站部署到IIS后访问不了,报错IIS管理器无法验证此内置账户是否有访问权
- CSS美化超级链接和鼠标
- 图灵机器人