您的位置:首页 > 移动开发 > Objective-C

objective-c runtime

2014-04-17 16:58 337 查看
本文根据苹果文档分析下objective-cruntime;简介Objective-c语言把许多compile、link处理都推迟runtime时处理。它尽可能的动态处理操作。这意味着objective-c不仅需要compiler,更需要一个runtimesystem去的执行编译后的代码(compiledcode).Runtimesystem的作用就像objective-c语言的一种操作系统(operatingsystem);使得这门语言正常工作。本文档主要要析下NSObjecclass以及Objective-cprograms怎样同runtimesystem交互.特别是,它探讨了runtime动态加载newclass的范例,以及向其它对象转发消息。而且,Itprovidesinformationabout
howyoucanfindinformationaboutobjectswhileyourprogramisrunning.一、怎样同runtime交互Objective-c程序与runtimesystem在三个不同的层次上交互:通过objective-csourcecode;通过Foundationframework中NSObjectclass定义的一些method;通过直接调用runtimefunctions;1.Objective-csourcecode大部分时间,runtimesystem在后台自动运行。只要你编写并且编译了Objective-C
sourcecode,runtimesystem在后台就自动运行。当你编译一些包含Objective-C
classesandmethods的代码时,编译器(compiler)就创建一些实现objective-c语言动态特性的datastructuresandfunctioncalls。这些data
structures从classandcategorydefinitionsandinprotocoldeclarations中捕获相应的信息;这些data
structuresalsoinclude在类以及协议的定义中声明的(discussedin“Defining
aClass”and“Protocols”)the
classandprotocolobjects,以及一些methodselectors,instance
variabletemplates,andotherinformationdistilledfromsourcecode.Runtime的主要功能是消息转发。2.NSObjectMethodsCocoa中的大部分objects都是
NSObject
class的子类,因此也继承了NSObject定义的方法(NSProxy除外)。因此,NSObject
定义的methods在它的子类对象或变量中,照样起作用。但在少数情况下,NSObject只定义一个模板forhowsomethingshouldbedone;它自身并不实现这些代码。比如,NSObjectclass定义了一个descriptioninstancemethod来返回一个描述类信息的string.它主要用于debugging-the
GDB
print-object
command打印出从该方法返回的string.
该方法
NSObject
的实现并不知道what
theclasscontains,因此它返回一个name+addressoftheobject的string.NSObject的子类可以实现该方法以返回更多详细信息.比如,NSArray中的description方法就返回该数组中包含的对象的descriptions.
一些NSObject的方法可以简单查询runtime
system的信息。这些方法允许objectstoperformintrospection.比如,classmethod
允许一个
object
来查询它的类;isKindOfClass:和isMemberOfClass:这两methods来确认一个object在继承树中的位置;respondsToSelector:该方法表明某object是否可以接收某个message;conformsToProtocol:方法表明一个object是否实现了某个protocol中定义的方法;methodForSelector:该方法则提供了某个方法的实现地址;
Methods
likethesegiveanobjecttheabilitytointrospectaboutitself.
3.RuntimeFunctionsRuntimesystem是一个动态的共享库,通过一个公共接口,由位于目录/
/usr/include/objc
内部头文件内一系列functions
anddatastructures组成;
其中的一些方法允许你用c语言去复制当你写objective-ccode时,编译器作了什么。其它则构成一些基础功能通过NSObjectMethod导出(OthersformthebasisforfunctionalityexportedthroughthemethodsoftheNSObject
class)。这些方法使开发者可以开一些runtime
system的interface,producetoolsthataugment(增强)thedevelopmentenvironment;当你programminginObjective-C时,并不需要用这些方法。但有一些runtimefunctions有些情况下在writinganObjective-Cprograms会很有用,这些方法的定义可以查看Objective-C
RuntimeReference.二、消息这章节描述messageexpressions是怎样converted
into
objc_msgSend
function
calls,以及怎样才能refertomethodsbyname。然后揭示怎样才能take
advantageof
objc_msgSend,怎样才能circumvent(规避)
dynamicbinding。
1、The
objc_msgSendFunction
在Objective-c中,messages直到runtime才绑定method
implementation.
编译器把message
expression:
[receivermessage];

转换成:acallonamessagingfunction,
objc_msgSend.This
Function把消息表达式中的receiver、
thenameofthemethod(themethodselector),作为自已的两个主要参数:
objc_msgSend(receiver,selector)

Messageexpression传来的任何参数,也由objc_msgSend处理:
objc_msgSend(receiver,selector,arg1,arg2,...)

objc_msgSend函数负责处理dynamicblinding:首先objc_msgSend根据selector参数找到method
implementation程序(procedure)片段.因同样的method可能被不同的class不同的实现,故the
preciseprocedure依赖于theclassofthereceiver.
然后objc_msgSend调用该方法实现代码(procedure),并传参数:receiver、any
argumentsthatwerespecifiedforthemethod.
最后objc_msgSend把该procedure的结果作为自己的返回结果(returnvalue)返回.注:The
compilergeneratescallstothemessagingfunction.Youshouldnevercallitdirectlyinthecodeyouwrite.消息转发的关键在于compiler为eachclassandobject生成的structures.每个classstructure都包含两个必要的元素:Apointertothesuperclass.Aclassdispatchtable.
该表中的每个条目都把methodselector和相应的class-specificaddressesofthemethodstheyidentify关联在一起.比如:Theselectorforthe
setOrigin::
method
isassociatedwiththeaddressof(theprocedurethatimplements)
setOrigin::,
andsoon.当一个object创建时,memoryforit分配,instance
variables初始化.Object’svariables中的第一个变量是一个指向它的classstructure指针(pointer)。该pointer(isa),使得该object可以访问itsclass,通过itsclass,访问到它所继承的所有classes.:虽然不是严格语言中的一部分,但对一个object来说,the
isapointer却是必须的,以便和runtimesystem交互。Anobject必须是“equivalent”toastruct
objc_object(objc/objc.h)在该structure定义的任何领域.但,你没必要定义自己的root
object,因任何NSObject或NSProxy的子类都自动的拥有isavariable.这些class
andobjectstructure'selements如以下插图所示:当向anobject发消息时,objc_msgSend函数根据该object'sisa指向的classstructure,在该classstructure的dispatchtable中找到对应的methodselector.若是找不到,objc_msgSend则根据该class
structure'ssuperclass指向的superclassstructure的dispatchtable中查找对应的methodselector.Successivefailures导致objc_msgSend沿着该object'sclasshierarchy继续向上寻找,直至NSObject
class.一旦定位到该selector,objc_msgSend函数就通过该selector对应的class-specificaddressesofmethodimplementation来调用该实现procedure,并传给它receiving
object’sdatastructure.这就是runtime时,methodimplementation被选择的方式.以面向对象编程的术语来说,叫做动态绑定到消息。为了加速messagingprocess,runtimesystem把用过的selectorsandtheaddressofmethods缓存起来.Eachclass都有一个单独的cache,它可以缓存theselectorsforinheritedmethods
aswellasmethodsdefinedintheclass.在查找dispatchtables之前,objc_msgSend通常先检查the
cacheofthereceivingobject’sclass.若是该selector在该cache中,messaging则直接执行上述过程.一旦程序已经运行足够久来“warmup”itscaches,那么大部分的消息都可在thecacheofthereceiving
object’sclass中找到它的实现.当程序运行后,Caches会动态的增长以容纳新的消息.2.Using
HiddenArguments当objc_msgSend找到a
method'simplementationprocedure,它就会调用该procedure并把所有参数传递给它.当然objc_msgSend也会把两个hiddenarguments传值给该procedure:ThereceivingobjectTheselectorforthemethod这两参数给每个methodimplementation关于调用它的消息表达式的明确信息。这些参数说成“hidden”是因为它们在定义该方法的源码中并没有定义.当程序is
compiled,它们是被插入到methodimplementation中的。虽然这些参数并没有被“explicitly”declared,源代码仍可引用它们(就像引用该receiving
object'sinstancevariables).Amethod使用self引用thereceivingobject,使用_cmd来引用itsownselector.在如下的例子中,_cmd指的是theselector
forthestrangemethod,self指的是theobjectthatreceivesastrangemessage.
-strange

{

idtarget=getTheReceiver();

SELmethod=getTheMethod();


if(target==self||method==_cmd)

returnnil;

return[targetperformSelector:method];

}

self
isthemoreusefulofthetwoarguments.Itis,infact,thewaythereceivingobject’sinstancevariablesaremadeavailabletothemethoddefinition.self的作用不止于此,实际上,它是thereceivingobject’sinstancevariables对函数定义(method
definition)起作用的方式。3.GettingaMethodAddress规避动态绑定(circumventdynamicbinding)的唯一方法是:获取函数地址(theaddressofamethod)并像调用function一样直接调用./**注:objectivc-c中,Method和function区别:Functions是一种与objective-cclass/object无关的函数块,从c语言继承而来.实际上就是一个标准的c语言函数.*用法如下:
*//declaration
*intfooFunction(){
*return0;
*}

*//call
*inta;
*a=fooFunction();
*相对应的,methods则必须和objective-cclass/object关联的方法,且只能通过class/object来调用它们。简言之:methods就是objective-c语言定义的函数.用法如下:
*//declaration
*-(int)fooMethod{
*return0;
*}

*//call
*inta;
*a=[someObjectOfThisClassfooMethod];

*/上述方式在有些罕见情况是比较合适:当某个method将被成功调用很多次,且你想避免每次函数调用时messaging(消息路由)的消耗.通过NSObject类的methodForSelector:方法,你可以得到一个指某函数实现的指针(apointertotheprocedurethatimplementsamethod),然后可以用该指针来调用函数实现程序块(use
thepointertocalltheprocedure).methodForSelector返回的pointer必须仔细强制(carefullycast
to)转换成theproperfunctiontype.且,return
andargumenttypes必须包含在该转换中。如下示例展示setFilled:method的方法实现procedure怎么被调用的:
void(*setter)(id,SEL,BOOL);

inti;


setter=(void(*)(id,SEL,BOOL))[target

methodForSelector:@selector(setFilled:)];

for(i=0;i<1000;i++)

setter(targetList[i],@selector(setFilled:),YES);

传给该Procedure的前两参数是:thereceivingobject(self)、themethodselector(_cmd).这两参数在methodsyntax(语法)中是隐藏的,但当amethodiscalledasafunction时,必须是显式的。用methodForSelector:来规避动态绑定可以节省objective-c中消息路由的大部分时间.但是,这种方式只有“某个消息被重复很多次”时,才有意义,比如forloop.注:methodForSelector:是由cocoaruntimesystem提供,它不是objective-c语言自己的特征.三、DynamicMethodResolution本章节介绍怎样动态的提供一个方法的实现(howtoprovideanimplementationofamethoddynamically).1、DynamicMethodResolution有时,你需要动态的提供一个方法的实现(provideanimplementationofamethoddynamically).比如,Objective-c中的dynamicproperties
directive:
@dynamicpropertyName;

该声明告诉compiler:和该property关联的methods将会动态的提供.通过实现
resolveInstanceMethod:
resolveClassMethod:方法,对于一个给定的selector
foraninstanceandclassmethod,可以分别动态的提供implementation.AnObjective-cmethod只是一个至少需要两个参数(
self
and
_cmd
)的简单的C
function.你可以通过class_addMethodfunction把一个C
function添加为amethodforaclass.对于如下给定function:
voiddynamicMethodIMP(idself,SEL_cmd){

//implementation....

}

可以用resolveInstanceMethod:动态添加为classmethod(called
resolveThisMethodDynamically
)likethis:
@implementationMyClass

+(BOOL)resolveInstanceMethod:(SEL)aSEL

{

if(aSEL==@selector(resolveThisMethodDynamically)){

class_addMethod([selfclass],aSEL,(IMP)dynamicMethodIMP,"v@:");

returnYES;

}

return[superresolveInstanceMethod:aSEL];

}

@end

Forwardingmethods和Dynamicmethodresolution很大部分都是交叉的.Aclass有机会在进入forwardingmechanism之前dynamicallyresolveamethod.若respondsToSelector:或instancesRespondToSelector:被调用,the
dynamicmethodresolver有机会提供anIMPfortheselectorfirst.若你实现了resolveInstanceMethod:实际上却想使某些
selectors通过forwardingmechanism来转发,你需要returnNOforthoseselectors.3、DynamicloadingObjective-c程序运行时可以loadandlinknewclassesandcategories.就像编译已经编译、link的代码一样,newcodeisincorporatedintotheprogram.Dynamicloading可以做很多不同的东西.比如,theSystemPreferencesapplication中的不同modules都是dynamically
loaded.在Cocoaenvironment中,dynamicloading平常用来allow
applicationstobecustomized.其他人写的一些模块,你可以像InterfaceBuilderloadscustompalettesandtheOSXSystemPreferencesapplicationloadscustom
preferencemodules一样,在runtime加载这它们.Theloadablemodules可以扩展whatyourapplicationcando.你提供framework,其他人则使用它来writecode.虽然Mach-O文件中,已经有一个runtimefunction(objc_loadModules,defined
in
objc/objc-load.h
)来处理dynamicloadingofObjective-Cmodules,Cocoa'sNSBundleclass也提供了一个更方便的interface来处理dynamicloading-one
that’sobject-orientedandintegratedwithrelatedservices.在Foundationframeworkreference中的NSBundleclass
可以查看它的特点及用法.在OSXABIMach-OFileFormatReference中可以查找关于Mach-O
files的信息.
四、MessageForwardingSendingamessage给一个不能处理该消息的object(thatdoesnothandlethatmessage)会抛出error.但是,在抛出error之前,runtimesystem会给receivingobject一个机会去处理该消息(handle
themessage).1、Forwarding若sendamessagetoanobjectthatdoesnothandlethatmessage,在发出error之前,runtimesystem会给receivingobject发送a
forwardInvocation:
message
withan
NSInvocationobject
作为自己唯一的参数.NSInvocation
object封闭了原始的消息及参数信息(the
originalmessageandthearguments).
你可以实现forwardInvocation:方法给该消息设定一个默认的响应(a
defaultresponsetothemessage),或者用其它的方式来avoidthiserror.forwardInvocation:平常用以forwardthemessagetoanotherobject.
为了看到forwarding的范围及意图,想象以下场景:首先,假定你设计了一个可以响应(responseto)negotiate消息的object,且你希望its
response包含anotherkindofobject'sresponse.你可以简单的实现这项功能,通过在该negotiate方法的实现中,passing
anegotiatemessagetotheotherobject.
更进一步,假定你希望yourobject’s
responsetoa
negotiate
message是一个response
implementedinanotherclass.一种实现方式是makeyourclassinheritthemethodfromtheotherclass.但不太可能这样做.很好的理由是:因为yourclassandtheclassthatimplements
negotiate
在继承树中的不同分枝(There
maybegoodreasonswhyyourclassandtheclassthatimplements
negotiate
are
indifferentbranchesoftheinheritancehierarchy.).
虽然yourclass不能直接继承negotiatemethod,但你可以通过class'smethodimplementation发送一个messagetoaninstance
oftheotherclass:
-(id)negotiate

{

if([someOtherObjectrespondsTo:@selector(negotiate)])

return[someOtherObjectnegotiate];

returnself;

}

这种方法有点笨,特别是有一组消息这样处理时.你得在每个方法的实现中像上面一样调用另一个class'smethod.而且,若在写代码时,你不知道thefullsetofmessagesyoumightwanttoforward时,这种方法不能处理.因为thefull
setofmessagesyoumightwanttoforward取决于runtime'sevents,且它会变动当asnewmethodsandclassesareimplementedinthefuture.forwardInvocation:
method对于上述问题提供了一个特别的解决方案,且该解决方案是动态的。
它的工作流程:当anobject因don'thaveamethodmatchingthe
selectorinamessage而无法responsetothemessage时,runtimesystem会通过发送forwardInvocation:message通知它.Everyobject都从NSObjectclass继承一个forwardInvocation:method.但是NSObject's
versionofthemethod只是简单调用doesNotRecognizeSelector:方法.通过自己overridingandimplementingNSObject'sforwardInvocation:方法,就有机会利用forwardInvocation:message来给other
objects转发消息(forwardmessages).
为了能forwardamessage,
forwardInvocation:
method仅需这样做:Determinewherethemessageshouldgo,andSendittherewithitsoriginalarguments.可以通过invokeWithTarget:
method来发送消息:
-(void)forwardInvocation:(NSInvocation*)anInvocation

{

if([someOtherObjectrespondsToSelector:

[anInvocationselector]])

[anInvocationinvokeWithTarget:someOtherObject];

else

[superforwardInvocation:anInvocation];

}

Theforwardedmessages'sreturnvalue被返回给theoriginalsender.所有类型的returnvalues都可以传递给thesender,包括ids,structures,double-precisionfloating-point
numbers等.AforwardInvocation:method的作用就像是a
distributioncenterforunrecognizedmessages,把它们实时分发给不同的receivers.或者它可以是一个中转站(transferstation),发送所有的消息到相同的目的地(sendingallmessagestothesamedestination).它可以translate
onemessageintoanother,也可以简单的“吞下”一些消息以致于该消息hasnoresponseandnoerror.AforwardInvocation:method
也可以把合并severalmessages到只有asingleresponse.具体forwardInvocation:究竟做些什么取决于它的实现.但是,The
opportunityitprovidesforlinkingobjectsinaforwardingchain,为programdesign提供了可能性.注:只有当invokeannotexistingmethodinthenominalreceiver时,theforwardInvocation:method才会处理这些信息.比如,若你希望
yourobjectforwardnegotiatemessagetoanotherobject,yourobject自身不能有negotiatemethod.若有,该消息将不会到达forwardInvocation:.查看更多关于forwardingandinvocations,你可以去NSInvocation
class文档中查看.2、消息转发和多继承(ForwardingandMultipleInheritance)Forwarding模拟inheritance,可以为objective-cprograms模拟出一些multiple
inheritance的效果.如下图:anobject通过forwardInvocation:转发消息,就像“inherit”amethodimplementationinanotherclass.在这个演示中,Warriorclass'sinstance转发一个negotiate消息给
一个Diplomatclass'sinstance.看起来Warrior
class'sinstance响应了negotiate消息,实际上是Diplomat
class'sinstance响应,而Warriorclass'sinstance转发了该响应的结果.Anobject通过forwardsamessage,从而"inherit"methodsfromtwobranchesoftheinheritancehierarchy:它自己的继承树以及响应消息的object's继承树.上述示例中,Warriorclass就像是inherit了Diplomat以及自己的superclass.Forwarding提供了典型的multipleinheritance的特征。但,他们之间有很大的差别:Multipleinheritance结合了其继承的父类的各种不同特性于asingleobject;它倾向于大型的、多方位的objects.而Forwarding则是assigns
separateresponsibilitiestodisparateobjects.它把问题分解给更小的objects,但通过一种对于messagesender透明的方式来关联thoseobjects.3、代理对象(SurrogateObjects)Forwarding不仅模拟了multipleinheritance,它也使得可能去开发一些represent
or“cover”moresubstantialobjects的lightweightobjects.代理(thesurrogate)代表了theotherobject以及发送给它的funnels
message.The
proxy就是这样一种surrogate.Aproxy负责forwardingmessagestoaremotereceiver的管理细节,确保argumentvalues的复制、连接的检索等等.但它并不试图做其它的什么功能;它不重复remoteobject的functionality,只是简单的给
remoteobject一个localaddress,该address可以receivemessagesinanotherapplication.其它种类的
surrogateobjects也是可能的.比如,假定你有一个objectthatmanipulatesalotofdata,它可能创建了acomplicatedimage或者readsthecontentsofafileondisk.设置该object会很费时(time-consuming),最好doitlazily,当你需要它时,或者systemresources暂时idle.同时,你至少需要aplaceholderforthisobject
以便其它objectsintheapplication能够functionproperly.在这种情况下,你可以initiallycreatea
lightweightsurrogateforit,而非完全加载式的创建该object.Thisobject可以自己dosomethings,比如请求数据,但大多数情况下,它仅仅holdaplaceforthelargerobject,并在合适的时候,转发消息给它(forwardmessagestoit).当该surrogate'sforwardInvocation:method最初接到amessagedestinedfortheotherobject,它得确保"thatobject"是存在,若不存在则创建.所有发送给thelargerobject的messages都通过thesurrogate,因此,thesurrogate和thelargerobject通常被作是同一个概念.3、消息转发和继承(ForwardingandInheritance)虽说forwarding可模拟Inheritance,但NSObject决不会混淆两者.respondsToSelector:和
isKindOfClass:这两方法只会在inheritancehierarchy中查找,决不会在forwardingchain中查找.比如,若要确定aWarriorobject是否responsetoanegotiatemessage,
if([aWarriorrespondsToSelector:@selector(negotiate)])

...

返回结果是NO,即使它可以正常接收
negotiatemessages并responsetothem,通过forwardingthemtoaDiplomat.很多情况下,NO是很合适.但有时,它不是.若你用forwarding来设置asurrogateobject或者来扩展thecapabilitiesofaclass,theforwardingmechanism就像inheritance一样透明(transparent).若你希望yourobjects就像真的inheritthebehavioroftheobjectstheyforwardmessagesto,你需要重新实现respondsToSelector:和
isKindOfClass:方法来包含你的forwardingalgorithm(算法):
-(BOOL)respondsToSelector:(SEL)aSelector

{

if([superrespondsToSelector:aSelector])

returnYES;

else{

/*Here,testwhethertheaSelectormessagecan*

*beforwardedtoanotherobjectandwhetherthat*

*objectcanrespondtoit.ReturnYESifitcan.*/

}

returnNO;

}

除了
respondsToSelector:和
isKindOfClass:方法,instancesRespondToSelector:method也需要反映theforwardingalgorithm.若是实现了某些protocols,conformsToProtocol:method同样也应当反映theforwardingalgorithm.同样,若一个object转发了任何它收到的remotemessages,那它需要实现method以便返回最终响应theforwardedmessages的方法的准确描述.比如,若anobjectforwardamessagetoitssurrogate,你得像下面一样实现methodSignatureForSelector:方法:
-(NSMethodSignature*)methodSignatureForSelector:(SEL)selector

{

NSMethodSignature*signature=[supermethodSignatureForSelector:selector];

if(!signature){

signature=[surrogatemethodSignatureForSelector:selector];

}

returnsignature;

}

你可以考虑把theforwardingalgorithm放在某处privatecode,比如method,以便其它的forwardInvocation:等方法来include(引用),调用它.注:这是一种advancedtechnique,只适合一些没有别的可能的解决方法(solution)的情形(situations).它并不希望作为一个多继承的替代品.若你必须要用到thistechnique时,必须确保你已经完全理解了thebehavioroftheclassdoingtheforwarding以及theclassyou'reforwardingto.这一小节中提到的一些方法都在
NSObject
class的声明中.在
NSInvocation
class的声明中,可以查看更多关于invokeWithTarget:的信息.五、TypeEncodings为辅助runtimesystem,thecompiler把thereturnandargumenttypesforeachmethod编码成(encodesin)acharacterstring,并把该string和对应的methodselector
关联起来.编码方式在其它一些情况下也有用,因此该编码方式用
@encode()
compiler
directive来实现.给定某个格式的type时,@encode()返回该type编码后的string.该type可以是基础类型比如anint,anpointer,ataggedstructureorunion,oraclassname等等,实际上,任何可以用作C
sizeof()
operator的参数任何type,都可以.
char*buf1=@encode(int**);

char*buf2=@encode(structkey);

char*buf3=@encode(Rectangle);

下面的这张表列出了thetypecodes.请注意,当你为了archivingordistribution而encodinganobject时,你所用的codes,和其中的很多都有交叉.但是,下面列出的codes,当你writeacoder时,其中的一些你不能用.当然,当你writeacoder时,也有一些你需要用的codes,不是由
@encode()生成.(想要查看更多关于
encodingobjectsforarchivingordistribution的信息,可以查看NSCoder
class
specification).Table6-1Objective-Ctypeencodings
Code
Meaning
c

A
char

i

An
int

s

A
short

l

A
long
l
istreatedasa32-bitquantityon64-bitprograms.
q

A
longlong

C

An
unsignedchar

I

An
unsignedint

S

An
unsignedshort

L

An
unsignedlong

Q

An
unsignedlonglong

f

A
float

d

A
double

B

AC++
bool
oraC99
_Bool

v

A
void

*

Acharacterstring(
char*
)
@

Anobject(whetherstaticallytypedortyped
id
)
#

Aclassobject(
Class
)
:

Amethodselector(
SEL
)
[arraytype]
Anarray
{name=type...}
Astructure
(name=type...)
Aunion
b
num
Abitfieldofnumbits
^
type
Apointertotype
?

Anunknowntype(amongotherthings,thiscodeisusedforfunctionpointers)
重要提示:Objective-C语言不支持
longdouble
type.
@encode(long
double)
returns
d
,和
@encode(double)编码一样
.Anarray'stypecode被包含在一对方括号之间;thenumberofelementsinthearray被放在第一个方括号之后,arraytype之前.比如,anarrayof12pointerstofloats编码如下:
[12^f]

Structures'stypecode被包含在一对大括号之间;unions则是括号之间.大括号之中首先列出thestructuretag,紧接着一个等号(equalsign),接下来则是该structure的每个参数字段的编码(codesfor
thefieldsofthestructurelistedinsequence).比如,如下结构体
typedefstructexample{

idanObject;

char*aString;

intanInt;

}Example;

将会这样编码:
{example=@*i}

无论是把thedefinedtypename(Example)还是thestructuretag(example)
传值给@encode()编码结果一样.Astructurepointer'sencoding和structure编码需要一样的内部参数信息,如下:
^{example=@*i}

但是,Astructurepointer'spointer则要去除内部的类型信息,即参数信息:
^^{example}

Objects'stypecode的处理和structures一样.比如,把NSObjectclassname传递给
@encode()
编译器指令后,得到如下结果:
{NSObject=#}

The
NSObject
class仅仅声明了一个
isainstancevariableoftypeclass.注:虽然
@encode()
指令没有返回,但the
runtimesystem使用另外的encodingsfortypequalifiers用来声明methodsinaprotocol,如下图所示:Objective-cmethodencodings:
Code
Meaning
r

const

n

in

N

inout

o

out

O

bycopy

R

byref

V

oneway

六、Properties的声明(Declaredproperties)当compiler遇到propertydeclarations时(见“DeclaredProperties”inTheobjective-cprogramminglanguage),它会生成一个与enclosingclass,categoryorprotocol关联的描述性元数据(descriptivemetadata).可以通过一些特定的functions来查看该metadata,这些functions支持通过name查找apropertyonaclass
orprotocol,获取作为an
@encode
string的propertytype,拷贝作为an
arrayofCstrings的property'sattributeslist.Alistofdeclaredproperties可以用于eachclassandprotocol.1、Property类型和Functions(PropertyTypeandFunctions)Propertystructure定义了一个指向apropertydescriptor的不透明的句柄,或者说一个指向propertydescriptor("不透明",因文档中没给出其定义)的指针.
typedefstructobjc_property*Property;

可以用
class_copyPropertyList和
protocol_copyPropertyList这两个function分别取出一个与aclass(includingloadedcategories)andaprotocol关联的propertiesarray:
objc_property_t*class_copyPropertyList(Classcls,unsignedint*outCount)

objc_property_t*protocol_copyPropertyList(Protocol*proto,unsignedint*outCount)

比如,给定以下classdeclaration:
@interfaceLender:NSObject{

floatalone;

}

@propertyfloatalone;

@end

你可以用如下方法取出thelistofproperties:
idLenderClass=objc_getClass("Lender");

unsignedintoutCount;

objc_property_t*properties=class_copyPropertyList(LenderClass,&outCount);

可以用
property_getNamefunction来发现aproperty'sname:
constchar*property_getName(objc_property_tproperty)

对于一个给定的property'sname,可以用
class_getProperty和
protocol_getProperty这两个functions来分别获取aclassandprotocol的相应的property'sreference:
objc_property_tclass_getProperty(Classcls,constchar*name)

objc_property_tprotocol_getProperty(Protocol*proto,constchar*name,BOOLisRequiredProperty,BOOLisInstanceProperty)

可以用
property_getAttributesfunction来发现thenameandthe@encodetypestringofaproperty.关于encodingtypestrings的详情,见“Type
Encodings”;关于thisstring的详情,见“Property
TypeString”和“Property
AttributeDescriptionExamples”.
constchar*property_getAttributes(objc_property_tproperty)

综合上面,可以用如下代码打印出aclass'spropertieslist:
idLenderClass=objc_getClass("Lender");

unsignedintoutCount,i;

objc_property_t*properties=class_copyPropertyList(LenderClass,&outCount);

for(i=0;i<outCount;i++){

objc_property_tproperty=properties[i];

fprintf(stdout,"%s%s\n",property_getName(property),property_getAttributes(property));

}

2、PropertyTypeString可以用
property_getAttributesfunction来查寻aproperty'sname、@encodetypestring,以及theproperty'sotherattributes.Thepropertytypeencodingstring,以
T开头,紧跟着the
@encode
type
和一个逗号,结尾以
V开头,紧跟着thenameofthebackinginstancevariable.
它们之间,theattributes由以下描述符(descriptors)指定,以逗号分开:Declaredpropertytypeencodings
Code
Meaning
R

Thepropertyisread-only(
readonly
).
C

Thepropertyisacopyofthevaluelastassigned(
copy
).
&

Thepropertyisareferencetothevaluelastassigned(
retain
).
N

Thepropertyisnon-atomic(
nonatomic
).
G<name>

Thepropertydefinesacustomgetterselectorname.Thenamefollowsthe
G
(forexample,
GcustomGetter,
).
S<name>

Thepropertydefinesacustomsetterselectorname.Thenamefollowsthe
S
(forexample,
ScustomSetter:,
).
D

Thepropertyisdynamic(
@dynamic
).
W

Thepropertyisaweakreference(
__weak
).
P

Thepropertyiseligible()forgarbagecollection.
t<encoding>

Specifiesthetypeusingold-styleencoding.
在"Property
AttributeDescriptionExamples",可以看到一些例子.3、PropertyAttributeDescription示例给定如下定义:
enumFooManChu{FOO,MAN,CHU};

structYorkshireTeaStruct{intpot;charlady;};

typedefstructYorkshireTeaStructYorkshireTeaStructType;

unionMoneyUnion{floatalone;doubledown;};

下表展示了一些propertydeclarations样品以及通过property_getAttributes返回的相应的string:
Propertydeclaration
Propertydescription
@propertycharcharDefault;

Tc,VcharDefault

@propertydoubledoubleDefault;

Td,VdoubleDefault

@propertyenumFooManChuenumDefault;

Ti,VenumDefault

@propertyfloatfloatDefault;

Tf,VfloatDefault

@propertyintintDefault;

Ti,VintDefault

@propertylonglongDefault;

Tl,VlongDefault

@propertyshortshortDefault;

Ts,VshortDefault

@propertysignedsignedDefault;

Ti,VsignedDefault

@propertystructYorkshireTeaStructstructDefault;

T{YorkshireTeaStruct="pot"i"lady"c},VstructDefault

@propertyYorkshireTeaStructTypetypedefDefault;

T{YorkshireTeaStruct="pot"i"lady"c},VtypedefDefault

@propertyunionMoneyUnionunionDefault;

T(MoneyUnion="alone"f"down"d),VunionDefault

@propertyunsignedunsignedDefault;

TI,VunsignedDefault

@propertyint(*functionPointerDefault)(char*);

T^?,VfunctionPointerDefault

@propertyididDefault;
Note:thecompilerwarns:
no'assign','retain',or'copy'attributeisspecified-'assign'isassumed"

T@,VidDefault

@propertyint*intPointer;

T^i,VintPointer

@propertyvoid*voidPointerDefault;

T^v,VvoidPointerDefault

@propertyintintSynthEquals;
Intheimplementationblock:
@synthesizeintSynthEquals=_intSynthEquals;

Ti,V_intSynthEquals

@property(getter=intGetFoo,setter=intSetFoo:)intintSetterGetter;

Ti,GintGetFoo,SintSetFoo:,VintSetterGetter

@property(readonly)intintReadonly;

Ti,R,VintReadonly

@property(getter=isIntReadOnlyGetter,readonly)intintReadonlyGetter;

Ti,R,GisIntReadOnlyGetter

@property(readwrite)intintReadwrite;

Ti,VintReadwrite

@property(assign)intintAssign;

Ti,VintAssign

@property(retain)ididRetain;

T@,&,VidRetain

@property(copy)ididCopy;

T@,C,VidCopy

@property(nonatomic)intintNonatomic;

Ti,VintNonatomic

@property(nonatomic,readonly,copy)ididReadonlyCopyNonatomic;

T@,R,C,VidReadonlyCopyNonatomic

@property(nonatomic,readonly,retain)ididReadonlyRetainNonatomic;

T@,R,&,VidReadonlyRetainNonatomic

费时好久,终于把这块内容给翻译完毕,收获多多..
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: