您的位置:首页 > 其它

使用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:来避免,如果有更好的方法,请告知。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: