Objective-C 编程语言官网文档(四)-协议
2012-06-01 18:10
363 查看
声明:本文档仅为个人学习过程中顺手翻译之作,方便开发的同胞借鉴参考。如有觉得译的不好不到位的地方,欢迎指正,将及时做出更正
尽量尊重原文档,因为首次Objective-C,有些地方可能直译了没有注意该语言的专有词,希望指正。如需转载,请注明出处
IDE:XCODE4.3.1
OS:MACOSX10.7.4
文章来译自:http://developer.apple.com/
协议
协议会声明一些可以被其它类实现的方法。协议通常在一下几种情况下很有用:
声明一些期待被实现的方法。
当为了隐藏一个对象的类而给其声明接口时。
为了捕获那些不存在继承关系的类的共同点
声明可以被实现的接口
类和类别接口声明一些方法,它们与一个特定的类联系在以其,这个类需要主要实现的一些方法。正式跟非正式的协议,声明的方法不依赖任何特定的类,但任何类,很多类都可以实现它的这些方法。协议只是一系列方法的声明,没有类的定义。例如,这些方法用来报告用户对鼠标的操作可以集合在一起,放在协议中:
-(void)mouseDown:(NSEvent*)theEvent; |
-(void)mouseDragged:(NSEvent*)theEvent; |
-(void)mouseUp:(NSEvent*)theEvent; |
协议让方法的声明从类继承的依赖中解脱出来,所以它们可以被用于任何类跟类目所不能够的方式去使用。协议的方法清单会(或者可能会)在某个地方被实现,但协议对是究竟是哪个类实现了它们毫无兴趣。它所感兴趣的是是否那个特定的类符合协议的要求—是否它实现了协议声明的那些方法。这样对象就按照类型分类就可以不仅仅基于基本的继承自相同类的产生的共同点,还可以基于基于它们符合相同协议产生的共同点。不相干的继承分支的类可能类型会很像,因为它们都符合相同的协议。
协议可以在面向对象设计中扮演一个很重要的角色,尤其是当一个项目要分散到很多实现者手中或者它包含在别的项目中的对象的时候。Cocoa软件大量的使用协议来支持Objective-C消息的进程间通信.
但是,一个Objective-C程序没必要使用那么多协议。不像类的定义和消息表达式,协议是可选的。一些Cocoa框架使用它们,一些不用。这取决于你手头的任务。
用于给别人实现的方法
如果你知道一个对象的类,你可以查看它的接口声明(以及它集成到的类的接口声明)来找出它是给什么消息进行响应。这些声明通知消息它可以接收。协议也提供了一个方法通知消息它的发送。通信是双向的;对象发送消息也接收消息。例如,一个对象可能责任委派一个特定的操作给另外的对象,或者它可能偶尔需要简单的请求另外的对象来获取信息。在一些情况下,一个对象可能乐意把它的动作通知其它对象,这样它们就可以采取任何要求的并行措施。
如果你要开发发送器类跟***类来作为同一个项目的一部分(或者如果另外某个人已经想你提供了***以及它的接口文件),这个通信很好协调。发送器只是简单的导入***的接口文件。导入的文件声明了发送器在它发送的消息中使用的方法选择器。
然而,如果你要开发一个对象,这个对象要发消息给一个它还没定义的对象—那个你留给其他人来实现的对象—你不必获得***的接口文件。你需要另外一种方式来声明你在消息中使用方法,不必实现。协议符合这个要求。它将类使用的方法通知编译器,也将需要声明的方法通知给其他实现者,以使它们的对象可以跟你的进行协作。
假设,你在开发一个对象,需要通过给另外一个对象发送
helpOut:以及其他消息来请求它的协助.你提供了一个
assistant实例变量来为这些消息记录outlet并声明了一个配套方法来设置这个实例变量。
这个方法让其他的对象把它们自己注册成你消息的潜在接受者:
-setAssistant:anObject |
{ |
assistant=anObject; |
} |
assistant,将会运行一个检查以确保接受者实现了一个它可以响应的方法:
-(BOOL)doWork |
{ |
... |
if([assistantrespondsToSelector:@selector(helpOut:)]){ |
[assistanthelpOut:self]; |
returnYES; |
} |
returnNO; |
} |
assistant,你只能为
helpOut:方法声明一个协议;
不用导入实现它的类的接口文件。
为匿名对象声明接口
协议可以用于声明一个匿名对象的方法,一个未知类的对象。一个匿名对象可能代表是一个服务或者处理有限的一组函数,尤其是当只需要该类型的一个对象时。(对象在顶一个应用的架构时扮演着一个基础角色,而且对象在使用前必须初始化,这对于匿名来说可不好)对象对它们的开发者来说不是匿名的,当然,当它们被开发者提供给别人的时候,它们就是匿名的了。例如下列情形:
有人要提供一个框架或者一套对象给其它人来使用,可以包含没有类名或者接口文件标识的对象。缺少名字和类接口的情况下,用户是无法创建类的接口实例的。取而代之的是,提供者必须给出一个现成的实例。通常来说,在另外一个类的方法来返回一个有用的对象:
idformatter=[receiverformattingService]; |
你可以发送Objective-C消息给远程对象—在别的应用中的对象。
每个应用都有它自己的结构,类,以及内部的逻辑。但是你无需知道另外一个应用是怎么工作的或者它的什么组件将与它通信。作为一个外部人员,你所需要知道的就是你可以发送什么消息(协议)以及在哪发送它们()
如果一个应用发布了一个对象来作为远程消息的潜在***,它就必须还发布一个协议,协议中声明该对象将用来响应那些消息的方法。它无需披露有关该对象的任何其它信息。发送消息的应用不需要知道该对象的类,亦不用在它自己的设计中使用那个类。它只需要那个协议就够了。
协议使匿名对象称为可能。没有了协议,就没办法给一个没有自己类标识的对象声明接口。
注意:即使一个匿名对象的提供者不返回它的类,但对象自身会在运行时返回它。一个类消息会返回这个匿名对象的类。然而,去发掘这些额外的信息没太大必要。在协议中的信息就足够了。
非继承的共性
如果多于一个类实现了一组方法,这些类通常根据一个抽象类分组,这个抽象类声明了它们公有的那些方法。每个子类可以按照它们自己的方式再实现这些方法,但继承关系以及在抽象类中的公有方法声明持有了子类的基本共性。然而,有时没办法通过抽象类分组公有方法。在大多方面都不相干的类仍然需要实现一些相似的方法。这种有限的共性可能不适合继承关系。例如,你可能想要在你的应用中添加对创建XM格式对象的支持,并用XML格式初始化变量:
-(NSXMLElement*)XMLRepresentation; |
-initFromXMLRepresentation:(NSXMLElement*)xmlString; |
对象可以通过这种共性(它们遵循的协议)赋予类型,而不是通过它们的类。例如,一个
NSMatrix实例必须跟代表它的单元的对象通信。matrix可以要求这些对象都是
NSCell类型(基于类的一种类型)
并且依赖于事实上所有从
NSCell类继承而来的对象都有用于回应
NSMatrix消息的方法.另外一种选择是,
NSMatrix对象可以要求代表单元的对象拥有可以响应一组特定消息(基于一种协议类型)的方法。这种情况下,
NSMatrix对象不用在意一个单元对象是属于什么类,只要它实现了那些方法就行。
FormalProtocols
Objective-C语言提供一种正式声明一组方法(包括属性的声明)的途径,这就是协议。正式的协议获得了这个语言以及运行时系统的良好支持。例如,编译器能够检查基于协议的类型,并且对象可以在运行时自省来报告它们是否遵循一个协议。
声明一个协议
通过一个@protocol指令来声明一个正式的协议:
@protocolProtocolName |
methoddeclarations |
@end |
@protocolMyXMLSupport |
-initFromXMLRepresentation:(NSXMLElement*)XMLElement; |
-(NSXMLElement*)XMLRepresentation; |
@end |
可选的协议方法
协议方法可以通过@optional关键字标识为可选.与
@optional关键字对应的,
还有个
@required关键字来正式指定默认行为。你可以使用
@optional跟
@required来将你的协议进行适当的分块。如果你没有指定任何关键字,那么默认为
@required.
@protocolMyProtocol |
-(void)requiredMethod; |
@optional |
-(void)anOptionalMethod; |
-(void)anotherOptionalMethod; |
@required |
-(void)anotherRequiredMethod; |
@end |
非正式协议
除了正式协议,你也可以定义一个非正式协议。通过将方法组织在一个类目声明中:@interfaceNSObject(MyXMLSupport) |
-initFromXMLRepresentation:(NSXMLElement*)XMLElement; |
-(NSXMLElement*)XMLRepresentation; |
@end |
NSObject类的类别,因为这将极大的将方法名与任何继承自
NSObject类的类联系起来。因为所有的类都是继承自根类,方法在继承树中的任何地方都没有什么严格限制。(同样可以把非正式协议作为两外一个类的类别,来把它限制在一个特定的继承树分支中,但这真心没什么必要)
在用于一个协议时,一个类别接口没有响应的实现。取而代之的是,实现协议的类在它们自己的接口文件中再次声明这些方法,并在它们的实现文件中把这些方法跟其它方法一起定义。
一个非正式协议改变了类别声明的规则,列出了一组方法,但没有将它们与任何特定类或者实现联系起来。
作为非正式协议,定义在类别中,并不能获得很多语言上的支持。既没有编译时的类型检查,运行时也不能检查一个对象是否遵循了这个协议。要获得这些支持,你必须使用正式协议。非正式协议可能当所有方法都是可选时比较有用,例如delegate,但是(在MacOSXv10.5以及更新的版本中)最好还是使用带有可选方法的正式协议;
协议对象
就像类对象在运行时代表类,选择器代码代表方法一样,一种特殊的数据类型代表了正式协议—协议类的实例.跟协议打交道的源码(而不是在一个类型配置中使用它)必须引用相应的协议对象。在许多时候,协议跟类的定义很像。它们都声明方法,并且在运行时都由对象代表—类是通过类的实例,协议则是协议的实例。向类对象一样,协议对象从源码中找到的声明跟定义自动被创建,并为运行时系统所使用。它们没有在程序源码中被分配并初始化。
源码可以通过使用
@protocol()指令来使用协议对象—跟声明协议的指令一样,当然,除了这里多了一对括号。括号中包含了协议名:
Protocol*myXMLSupportProtocol=@protocol(MyXMLSupport); |
@protocol()里面。
编译器为每个它遇到的协议声明创建一个协议对象,但仅当该协议同时也是:
被一个类所采用,或者
在源码中某个地方被引用(使用
@protocol())
在运行时,不会有协议变量代表那些声明了但没有使用的协议(除非像下面描述的类型检查)
采用一个协议
采用一个协议类似于用某种方法声明一个父类。因为两者都会给这个类分配方法。父类的声明分配它继承的方法。协议分配声明在协议列表中的方法。如果一个类在它的声明中,把协议列在了它的父类名后面的尖括号中,我们就说它采用了一个正式协议,@interfaceClassName:ItsSuperclass<protocollist> |
@interfaceClassName(CategoryName)<protocollist> |
@interfaceFormatter:NSObject<Formatting,Prettifying> |
采用了协议的类或者类别必须导入协议位置头文件。声明在被采用了的协议中的方法不会在类或者类接口中再次声明。
一个类可以仅仅采用协议而不定义别的其它方法。例如,下例中的类就仅仅是声明采用了两个协议,并没声明别的实例变量或者它自己的方法。
@interfaceFormatter:NSObject<Formatting,Prettifying> |
@end |
遵循协议
如果一个类采用了正式协议或者继承了一个采用了正式协议的类,那么我们就说它遵循了该协议。而且该类的实例跟它的类遵循了相同的一组协议。因为类必须实现它所采用的协议中声明的要求实现的所有方法,所以说一个类或者实例遵循了一个协议就等于说它集成了所有声明在协议中的方法。
我们可以通过给一个对象发送
消息来检查其是否遵循了某个协议.conformsToProtocol:
if(![receiverconformsToProtocol:@protocol(MyXMLSupport)]){ |
//ObjectdoesnotconformtoMyXMLSupportprotocol |
//Ifyouareexpectingreceivertoimplementmethodsdeclaredinthe |
//MyXMLSupportprotocol,thisisprobablyanerror |
} |
.)conformsToProtocol:
conformsToProtocol:的测试就像
对单个方法的测试,respondsToSelector:
除了这里是测试协议是否被很好遵循(并且可能它声明的所有方法都被实现了)而不是仅仅看是否某个特定的方法是否被实现。因为它会检查所有协议中的方法,
conformsToProtocol:比
更有效。respondsToSelector:
conformsToProtocol:测试也跟
isKindOfClass:测试有点相像,
除了前者是测试是否一个类型是基于协议的而不是基于继承关系的类型。
类型检查
可以扩展对象的类型声明来包含正式协议。这样协议可以提供给编译器另外一种级别的类型检查,会更加抽象,因为它没有跟特定实现绑定。在类型声明中,协议名列在类型名后面的尖括号里。
-(id<Formatting>)formattingService; |
id<MyXMLSupport>anObject; |
例如,假如
Formatter是一个抽象类,声明如下
Formatter*anObject; |
相似的,我们声明
id<Formatting>anObject; |
在每个案例中,都是将相似对象归类—或者因为它们共享公共的继承,或者说它们聚集了一组通用方法。
这两种类型可以合并到一个声明中:
Formatter<Formatting>*anObject; |
conformsToProtocol:消息进行响应.)
协议中的协议
协议中可以使用其它协议,语法跟类采用一个协议一样。@protocolProtocolName<protocollist> |
Paging协议结合了
Formatting协议
@protocolPaging<Formatting> |
Paging协议的对象也都遵循
Formatting.类型声明如下
id<Paging>someObject; |
conformsToProtocol:消息如下
if([anotherObjectconformsToProtocol:@protocol(Paging)]) |
... |
Paging协议检测了
Formatting的遵循性。
当一个类采用了一个协议,它就必须实现协议声明的所有要求实现的方法。另外,它必须遵循它所采用的协议中集成的其它所有协议。如果一个被集合的协议还集合了别的协议,这个类就必须遵循所有这些协议。类抗议通过下面集中技术来遵循协议:
实现协议声明的要求实现的方法。
继承一个已经采用并实现了该协议的类。
假设,
Pager类采用了
Paging协议.要是
Pager是
NSObject的子类:
@interfacePager:NSObject<Paging> |
Paging的方法,包括声明在集成的
Formatting协议中的方法。
另一方面,如果
Pager是
Formatter(任意一个采用了
Formatting协议的类)的子类
@interfacePager:Formatter<Paging> |
Paging协议中的方法,但声明在
Formatting中的则不用。
Pager继承了Formatter对
Formatting协议的遵循。
要注意类可以不用正式采用一个协议就能遵循该协议,只用简单的实现声明在协议中的方法就可以了。
引用其它协议
当跟复杂的应用打交道时,你偶尔会发现你写的代码看起来是这样的:#import"B.h" |
@protocolA |
-foo:(id<B>)anObject; |
@end |
B声明如下
#import"A.h" |
@protocolB |
-bar:(id<A>)anObject; |
@end |
@protocol指令对需要的协议做一个正向引用,来取代导入定义协议的接口文件。
@protocolB; |
@protocolA |
-foo:(id<B>)anObject; |
@end |
@protocol指令时,在这种写法中只是简单的通知编译器,
B是一个晚些时候会定义协议。不能导入
B协议所在文件。
英文原文:(
Protocols
Protocolsdeclaremethodsthatcanbeimplementedbyanyclass.Protocolsareusefulinatleastthreesituations:
Todeclaremethodsthatothersareexpectedtoimplement
Todeclaretheinterfacetoanobjectwhileconcealingitsclass
Tocapturesimilaritiesamongclassesthatarenothierarchicallyrelated
DeclaringInterfacesforOtherstoImplement
Classandcategoryinterfacesdeclaremethodsthatareassociatedwithaparticularclass—mainlymethodsthattheclassimplements.Informalandformalprotocols,ontheotherhand,declaremethodsthatareindependentof
anyspecificclass,butwhichanyclass,andperhapsmanyclasses,mightimplement.
Aprotocolissimplyalistofmethoddeclarations,unattachedtoaclassdefinition.Forexample,thesemethodsthatreportuseractionsonthemousecouldbegatheredintoaprotocol:
-(void)mouseDown:(NSEvent*)theEvent; |
-(void)mouseDragged:(NSEvent*)theEvent; |
-(void)mouseUp:(NSEvent*)theEvent; |
Protocolsfreemethoddeclarationsfromdependencyontheclasshierarchy,sotheycanbeusedinwaysthatclassesandcategoriescannot.Protocolslistmethodsthatare(ormaybe)implementedsomewhere,but
theidentityoftheclassthatimplementsthemisnotofinterest.Whatisofinterestiswhetherornotaparticularclassconformsto
theprotocol—whetherithasimplementationsofthemethodstheprotocoldeclares.Thusobjectscanbegroupedintotypesnotjustonthebasisofsimilaritiesresultingfrominheritingfromthesameclass,butalsoonthebasisoftheirsimilarityinconforming
tothesameprotocol.Classesinunrelatedbranchesoftheinheritancehierarchymightbetypedalikebecausetheyconformtothesameprotocol.
Protocolscanplayasignificantroleinobject-orienteddesign,especiallywhenaprojectisdividedamongmanyimplementorsoritincorporatesobjectsdevelopedinotherprojects.Cocoasoftwareusesprotocols
heavilytosupportinterprocesscommunicationthroughObjective-Cmessages.
However,anObjective-Cprogramdoesn’tneedtouseprotocols.Unlikeclassdefinitionsandmessageexpressions,they’reoptional.SomeCocoaframeworksusethem;somedon’t.Italldependsonthetaskathand.
MethodsforOtherstoImplement
Ifyouknowtheclassofanobject,youcanlookatitsinterfacedeclaration(andtheinterfacedeclarationsoftheclassesitinheritsfrom)tofindwhatmessagesitrespondsto.Thesedeclarationsadvertisethemessagesitcanreceive.Protocolsprovideawayforittoalsoadvertisethemessagesitsends.
Communicationworksbothways;objectssendmessagesaswellasreceivethem.Forexample,anobjectmightdelegateresponsibilityforacertainoperationtoanotherobject,oritmayonoccasionsimplyneed
toaskanotherobjectforinformation.Insomecases,anobjectmightbewillingtonotifyotherobjectsofitsactionssothattheycantakewhatevercollateralmeasuresmightberequired.
Ifyoudeveloptheclassofthesenderandtheclassofthereceiveraspartofthesameproject(orifsomeoneelsehassuppliedyouwiththereceiveranditsinterfacefile),thiscommunicationiseasilycoordinated.
Thesendersimplyimportstheinterfacefileofthereceiver.Theimportedfiledeclaresthemethodselectorsthesenderusesinthemessagesitsends.
However,ifyoudevelopanobjectthatsendsmessagestoobjectsthataren’tyetdefined—objectsthatyou’releavingforotherstoimplement—youwon’thavethereceiver’sinterfacefile.Youneedanotherway
todeclarethemethodsyouuseinmessagesbutdon’timplement.Aprotocolservesthispurpose.Itinformsthecompileraboutmethodstheclassusesandalsoinformsotherimplementorsofthemethodstheyneedtodefinetohavetheirobjectsworkwithyours.
Suppose,forexample,thatyoudevelopanobjectthatasksfortheassistanceofanotherobjectbysendingit
helpOut:andother
messages.Youprovidean
assistantinstancevariabletorecordtheoutletforthesemessagesanddefineacompanionmethodtosettheinstancevariable.This
methodletsotherobjectsregisterthemselvesaspotentialrecipientsofyourobject’smessages:
-setAssistant:anObject |
{ |
assistant=anObject; |
} |
assistant,acheckismadetobesurethatthereceiverimplementsamethodthat
canrespond:
-(BOOL)doWork |
{ |
... |
if([assistantrespondsToSelector:@selector(helpOut:)]){ |
[assistanthelpOut:self]; |
returnYES; |
} |
returnNO; |
} |
assistant,youcan
onlydeclareaprotocolforthe
helpOut:method;youcan’timporttheinterfacefileoftheclassthatimplementsit.
DeclaringInterfacesforAnonymousObjects
Aprotocolcanbeusedtodeclarethemethodsofananonymousobject,anobjectofunknownclass.Ananonymousobjectmayrepresentaserviceorhandlealimitedsetoffunctions,especiallywhenonlyoneobjectofitskindisneeded.(Objectsthatplayafundamentalroleindefininganapplication’sarchitectureandobjects
thatyoumustinitializebeforeusingarenotgoodcandidatesforanonymity.)
Objectsarenotanonymoustotheirdevelopers,ofcourse,buttheyareanonymouswhenthedevelopersuppliesthemtosomeoneelse.Forexample,considerthefollowingsituations:
Someonewhosuppliesaframeworkorasuiteofobjectsforotherstousecanincludeobjectsthatarenotidentifiedbyaclassnameoraninterfacefile.Lackingthenameandclassinterface,
usershavenowayofcreatinginstancesoftheclass.Instead,thesuppliermustprovideaready-madeinstance.Typically,amethodinanotherclassreturnsausableobject:
idformatter=[receiverformattingService]; |
identifyatleastsomeofthemessagesthatitcanrespondto.Themessagesareidentifiedbyassociatingtheobjectwithalistofmethodsdeclaredinaprotocol.
YoucansendObjective-Cmessagestoremoteobjects—objects
inotherapplications.
Eachapplicationhasitsownstructure,classes,andinternallogic.Butyoudon’tneedtoknowhowanotherapplicationworksorwhatitscomponentsaretocommunicatewithit.Asanoutsider,allyouneed
toknowiswhatmessagesyoucansend(theprotocol)andwheretosendthem(thereceiver).
Anapplicationthatpublishesoneofitsobjectsasapotentialreceiverofremotemessagesmustalsopublishaprotocoldeclaringthemethodstheobjectwillusetorespondtothosemessages.
Itdoesn’thavetodiscloseanythingelseabouttheobject.Thesendingapplicationdoesn’tneedtoknowtheclassoftheobjectorusetheclassinitsowndesign.Allitneedsistheprotocol.
Protocolsmakeanonymousobjectspossible.Withoutaprotocol,therewouldbenowaytodeclareaninterfacetoanobjectwithoutidentifyingitsclass.
Note:Eventhoughthesupplierofananonymousobjectdoesn’trevealitsclass,theobjectitselfrevealsitatruntime.Aclassmessagereturnstheanonymousobject’sclass.However,there’s
usuallylittlepointindiscoveringthisextrainformation;theinformationintheprotocolissufficient.
NonhierarchicalSimilarities
Ifmorethanoneclassimplementsasetofmethods,thoseclassesareoftengroupedunderanabstractclassthatdeclaresthemethodstheyhaveincommon.Eachsubclasscanreimplementthemethodsinitsownway,buttheinheritancehierarchyandthecommondeclarationintheabstractclasscapturetheessentialsimilaritybetweenthesubclasses.
However,sometimesit’snotpossibletogroupcommonmethodsinanabstractclass.Classesthatareunrelatedinmostrespectsmightneverthelessneedtoimplementsomesimilarmethods.Thislimitedsimilarity
maynotjustifyahierarchicalrelationship.Forexample,youmightwanttoaddsupportforcreatingXMLrepresentationsofobjectsinyourapplicationandforinitializingobjectsfromanXMLrepresentation:
-(NSXMLElement*)XMLRepresentation; |
-initFromXMLRepresentation:(NSXMLElement*)xmlString; |
Objectscanbetypedbythissimilarity(theprotocolstheyconformto),ratherthanbytheirclass.Forexample,an
NSMatrixinstance
mustcommunicatewiththeobjectsthatrepresentitscells.Thematrixcouldrequireeachoftheseobjectstobeakindof
NSCell(atypebasedonclass)andrelyonthefact
thatallobjectsthatinheritfromthe
NSCellclasshavethemethodsneededtorespondto
NSMatrixmessages.
Alternatively,the
NSMatrixobjectcouldrequireobjectsrepresentingcellstohavemethodsthatcanrespondtoaparticularsetofmessages(atypebasedonprotocol).In
thiscase,the
NSMatrixobjectwouldn’tcarewhatclassacellobjectbelongedto,justthatitimplementedthemethods.
FormalProtocols
TheObjective-Clanguageprovidesawaytoformallydeclarealistofmethods(includingdeclaredproperties)asaprotocol.Formalprotocolsaresupportedbythelanguageandtheruntimesystem.Forexample,thecompilercancheckfortypesbasedonprotocols,andobjectscanintrospectatruntimetoreportwhetherornotthey
conformtoaprotocol.
DeclaringaProtocol
Youdeclareformalprotocolswiththe@protocoldirective:
@protocolProtocolName |
methoddeclarations |
@end |
@protocolMyXMLSupport |
-initFromXMLRepresentation:(NSXMLElement*)XMLElement; |
-(NSXMLElement*)XMLRepresentation; |
@end |
OptionalProtocolMethods
Protocolmethodscanbemarkedasoptionalusingthe@optionalkeyword.Correspondingtothe
@optionalmodal
keyword,thereisa
@requiredkeywordtoformallydenotethesemanticsofthedefaultbehavior.Youcanuse
@optionaland
@requiredto
partitionyourprotocolintosectionsasyouseefit.Ifyoudonotspecifyanykeyword,thedefaultis
@required.
@protocolMyProtocol |
-(void)requiredMethod; |
@optional |
-(void)anOptionalMethod; |
-(void)anotherOptionalMethod; |
@required |
-(void)anotherRequiredMethod; |
@end |
InformalProtocols
Inadditiontoformalprotocols,youcanalsodefineaninformalprotocolbygroupingthemethodsinacategorydeclaration:@interfaceNSObject(MyXMLSupport) |
-initFromXMLRepresentation:(NSXMLElement*)XMLElement; |
-(NSXMLElement*)XMLRepresentation; |
@end |
NSObjectclass,
becausethatbroadlyassociatesthemethodnameswithanyclassthatinheritsfrom
NSObject.Becauseallclassesinheritfromtherootclass,themethodsaren’trestricted
toanypartoftheinheritancehierarchy.(Itisalsopossibletodeclareaninformalprotocolasacategoryofanotherclasstolimitittoacertainbranchoftheinheritancehierarchy,butthereislittlereasontodoso.)
Whenusedtodeclareaprotocol,acategoryinterfacedoesn’thaveacorrespondingimplementation.Instead,classesthatimplementtheprotocoldeclarethemethodsagainintheirowninterfacefilesanddefine
themalongwithothermethodsintheirimplementationfiles.
Aninformalprotocolbendstherulesofcategorydeclarationstolistagroupofmethodsbutnotassociatethemwithanyparticularclassorimplementation.
Beinginformal,protocolsdeclaredincategoriesdon’treceivemuchlanguagesupport.There’snotypecheckingatcompiletimenoracheckatruntimetoseewhetheranobjectconformstotheprotocol.Toget
thesebenefits,youmustuseaformalprotocol.Aninformalprotocolmaybeusefulwhenallthemethodsareoptional,suchasforadelegate,but(inMacOSXv10.5andlater)itistypicallybettertouseaformalprotocolwithoptionalmethods.
ProtocolObjects
Justasclassesarerepresentedatruntimebyclassobjectsandmethodsbyselectorcodes,formalprotocolsarerepresentedbyaspecialdatatype—instancesoftheProtocolclass.
Sourcecodethatdealswithaprotocol(otherthantouseitinatypespecification)mustrefertothecorrespondingprotocolobject.
Inmanyways,protocolsaresimilartoclassdefinitions.Theybothdeclaremethods,andatruntimethey’rebothrepresentedbyobjects—classesbyinstancesof
Classand
protocolsbyinstancesof
Protocol.Likeclassobjects,protocolobjectsarecreatedautomaticallyfromthedefinitionsanddeclarationsfoundinsourcecodeandareusedby
theruntimesystem.They’renotallocatedandinitializedinprogramsourcecode.
Sourcecodecanrefertoaprotocolobjectusingthe
@protocol()directive—thesamedirectivethatdeclaresaprotocol,except
thathereithasasetoftrailingparentheses.Theparenthesesenclosetheprotocolname:
Protocol*myXMLSupportProtocol=@protocol(MyXMLSupport); |
@protocol().
Thecompilercreatesaprotocolobjectforeachprotocoldeclarationitencounters,butonlyiftheprotocolisalso:
Adoptedbyaclass,or
Referredtosomewhereinsourcecode(using
@protocol())
Protocolsthataredeclaredbutnotused(exceptfortypecheckingasdescribedbelow)aren’trepresentedbyprotocolobjectsatruntime.
AdoptingaProtocol
Adoptingaprotocolissimilarinsomewaystodeclaringasuperclass.Bothassignmethodstotheclass.Thesuperclassdeclarationassignsitinheritedmethods;theprotocolassignsitmethodsdeclaredintheprotocollist.Aclassissaidtoadoptaformalprotocolifinitsdeclarationitliststheprotocolwithinanglebrackets
afterthesuperclassname:
@interfaceClassName:ItsSuperclass<protocollist> |
@interfaceClassName(CategoryName)<protocollist> |
@interfaceFormatter:NSObject<Formatting,Prettifying> |
declaredinthetwoprotocolsitadopts,inadditiontoanyitmighthavedeclareditself.
Aclassorcategorythatadoptsaprotocolmustimporttheheaderfilewheretheprotocolisdeclared.Themethodsdeclaredintheadoptedprotocolarenotdeclaredelsewhereintheclassorcategoryinterface.
It’spossibleforaclasstosimplyadoptprotocolsanddeclarenoothermethods.Forexample,thefollowingclassdeclarationadoptsthe
Formattingand
Prettifyingprotocols,
butdeclaresnoinstancevariablesormethodsofitsown:
@interfaceFormatter:NSObject<Formatting,Prettifying> |
@end |
ConformingtoaProtocol
Aclassissaidtoconformtoaformalprotocolifitadoptstheprotocolorinheritsfromanotherclassthatadoptsit.Aninstanceofaclassissaidtoconformtothesamesetofprotocolsitsclassconformsto.
Becauseaclassmustimplementalltherequiredmethodsdeclaredintheprotocolsitadopts,sayingthataclassoraninstanceconformstoaprotocolisequivalenttosayingthatithasinitsrepertoireall
themethodstheprotocoldeclares.
It’spossibletocheckwhetheranobjectconformstoaprotocolbysendingita
message.conformsToProtocol:
if(![receiverconformsToProtocol:@protocol(MyXMLSupport)]){ |
//ObjectdoesnotconformtoMyXMLSupportprotocol |
//Ifyouareexpectingreceivertoimplementmethodsdeclaredinthe |
//MyXMLSupportprotocol,thisisprobablyanerror |
} |
.)conformsToProtocol:
The
conformsToProtocol:testislikethe
testrespondsToSelector:
forasinglemethod,exceptthatittestswhetheraprotocolhasbeenadopted(andpresumablyallthemethodsitdeclaresimplemented)ratherthanjustwhetheroneparticularmethodhasbeenimplemented.Becauseitchecksforallthemethodsintheprotocol,
conformsToProtocol:can
bemoreefficientthan
.respondsToSelector:
The
conformsToProtocol:testisalsolikethe
isKindOfClass:test,
exceptthatittestsforatypebasedonaprotocolratherthanatypebasedontheinheritancehierarchy.
TypeChecking
Typedeclarationsforobjectscanbeextendedtoincludeformalprotocols.Protocolsthusofferthepossibilityofanotherleveloftypecheckingbythecompiler,onethat’smoreabstractsinceit’snottiedtoparticularimplementations.
Inatypedeclaration,protocolnamesarelistedbetweenanglebracketsafterthetypename:
-(id<Formatting>)formattingService; |
id<MyXMLSupport>anObject; |
Forexample,if
Formatterisanabstractclass,thedeclaration
Formatter*anObject; |
Similarly,thedeclaration
id<Formatting>anObject; |
tothetype.
Ineachcase,thetypegroupssimilarobjects—eitherbecausetheyshareacommoninheritance,orbecausetheyconvergeonacommonsetofmethods.
Thetwotypescanbecombinedinasingledeclaration:
Formatter<Formatting>*anObject; |
respondtoa
conformsToProtocol:message.)
ProtocolsWithinProtocols
Oneprotocolcanincorporateotherprotocolsusingthesamesyntaxthatclassesusetoadoptaprotocol:
@protocolProtocolName<protocollist> |
Pagingprotocol
incorporatesthe
Formattingprotocol
@protocolPaging<Formatting> |
Pagingprotocol
alsoconformsto
Formatting.Typedeclarationssuchas
id<Paging>someObject; |
conformsToProtocol:messagessuchas
if([anotherObjectconformsToProtocol:@protocol(Paging)]) |
... |
Pagingprotocoltotestforconformanceto
Formattingas
well.
Whenaclassadoptsaprotocol,itmustimplementtherequiredmethodstheprotocoldeclares,asmentionedearlier.Inaddition,itmustconformtoanyprotocolstheadoptedprotocolincorporates.Ifanincorporated
protocolincorporatesstillotherprotocols,theclassmustalsoconformtothem.Aclasscanconformtoanincorporatedprotocolusingeitherofthesetechniques:
Implementingthemethodstheprotocoldeclares
Inheritingfromaclassthatadoptstheprotocolandimplementsthemethods
Suppose,forexample,thatthe
Pagerclassadoptsthe
Pagingprotocol.
If
Pagerisasubclassof
NSObjectasshownhere:
@interfacePager:NSObject<Paging> |
Pagingmethods,includingthosedeclaredintheincorporated
Formattingprotocol.
Itadoptsthe
Formattingprotocolalongwith
Paging.
Ontheotherhand,if
Pagerisasubclassof
Formatter(a
classthatindependentlyadoptsthe
Formattingprotocol)asshownhere:
@interfacePager:Formatter<Paging> |
Pagingprotocolproper,butnotthosedeclaredin
Formatting.
Pagerinherits
conformancetothe
Formattingprotocolfrom
Formatter.
Notethataclasscanconformtoaprotocolwithoutformallyadoptingit,simplybyimplementingthemethodsdeclaredintheprotocol.
ReferringtoOtherProtocols
Whenworkingoncomplexapplications,youoccasionallyfindyourselfwritingcodethatlookslikethis:#import"B.h" |
@protocolA |
-foo:(id<B>)anObject; |
@end |
Bisdeclaredlikethis:
#import"A.h" |
@protocolB |
-bar:(id<A>)anObject; |
@end |
@protocoldirective
tomakeaforwardreferencetotheneededprotocolinsteadofimportingtheinterfacefilewheretheprotocolisdefined:
@protocolB; |
@protocolA |
-foo:(id<B>)anObject; |
@end |
@protocoldirectiveinthismannersimplyinformsthecompilerthat
Bis
aprotocoltobedefinedlater.Itdoesn’timporttheinterfacefilewhereprotocol
Bisdefined.
相关文章推荐
- Objective-C 编程语言官网文档(一)-简介
- Objective-C 编程语言官网文档(七)-关联引用
- Objective-C 编程语言官网文档(五)-属性的声明
- Objective-C 编程语言官网文档(八)-快速枚举
- Objective-C 编程语言官网文档(六)-类别以及扩展
- Objective-C 编程语言官网文档(三)-如何定义类
- Objective-C 编程语言官网文档(三)-如何定义类
- Objective-C 编程语言官网文档(九)-静态行为
- Objective-C 编程语言官网文档(十一)-异常的处理
- Objective-C 编程语言官网文档(十三 终结篇)-词汇表
- Objective-C 编程语言官网文档(九)-静态行为
- Objective-C 编程语言官网文档(十一)-异常的处理
- Objective-C 编程语言官网文档(十三 终结篇)-词汇表
- Objective-C 编程语言官网文档(五)-属性的声明
- Objective-C 编程语言官网文档(二)-对象,类以及消息
- Objective-C 编程语言官网文档(十二)-线程
- Objective-C 编程语言官网文档(十二)-线程
- Objective-C 编程语言官网文档(十)-选择器
- Objective-C 编程语言官网文档(一)-简介
- Objective-C 编程语言官网文档(五)-属性的声明