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

Objective-c key-value coding programming

2014-05-12 10:36 155 查看
一、简介(Introduction)

本文档描述了the
NSKeyValueCodinginformalprotocol,该protocol定义了一种允许程序通过name(orkey)间接访问anobject'sproperties的机制,而非通过直接调用anaccessormethod或instancevariables.

本文档简单介绍在程序中如何使用key-valuecoding,如何使你的classeskey-valuecodingcompliantforinteractingwithothertechnologies.Key-valuecoding使用key-valueobserving,Cocoabindings,Coredata等技术的基础技术(fundamentaltechnology).

1、文档的组织架构

Key-valuecoding包括以下文章:

“What
IsKey-ValueCoding?”提供了key-valuecoding的概述.

“Terminology”定义了用以引用(refer
to)anobject'sproperties的术语.

“Key-Value
CodingFundamentals”描述了使用key-valuecoding必须的基础原则.

“Key-Value
CodingAccessorMethods”描述了你的classes应当实现的accessormethods.

“Key-Value
Validation”描述如何实现propertyvalidation.

“Ensuring
KVCCompliance”描述了一个类(class)必须实现的功能(capabilities)以便该classtobekey-valuecodingcompliant.

“Scalar
andStructureSupport”描述了key-valuecoding支持的datatypes.

“Collection
Operators”列出了theavailablecollectionoperators并描述它们的用法.

“Accessor
SearchImplementationDetails”explainshowtheappropriateaccessormethodorinstancevariableisdetermined.

“Describing
PropertyRelationships”描述了使用meta-data来定义therelationshipsbetweenobjectsandtheirproperties.

“Performance
Considerations”描述了使用key-valuecoding的性能方面的一些注意事项.

Key-Value
ObservingProgrammingGuidedescribesthefeaturesofthekey-valueobservingprotocolthatallowsobjectstoobservechangesinotherobjects.

二、什么是Key-ValueCoding?

Key-valuecoding是一种间接访问一个对象的属性的机制(accessinganobject'spropertiesindirectly),usingstringstoidentifyproperties,而不是通过调用anaccessormethod,或者通过instancevariables直接访问.根本上来讲,key-valuecoding定义了程序的访问器方法实现(theapplication'saccessormethodsimplement)
的模式及方法签名(thepatternsandmethodsignatures).

Accessormethods,顾名思议,提供对程序中数据模型的属性值(theapplication'sdatamodel'spropertyvalues)的访问.Accessormethods有两种形式:getaccessors及setaccessors.
Getaccessors,也称作getters,returnthevaluesofaproperty.Setaccessors,也称作setters,setthevalueofaproperty.也有一些getter及setter变种来处理两个对象间的属性及一些to-manyrelationships.

程序中实现key-valuecoding兼容的accessors是一种重要的设计原则.Accessors对于执行合适的数据封装(enforceproperdataencapsulation)及其它技术的整合很有用,比如:key-valueobserving,CoreData,Cocoabindings,scriptability等.很多情况下,key-valuecodingmethods可用于简化程序的代码.

Key-valuecoding的基本方法在
NSKeyValueCoding声明,其默认实现由 NSObject 提供.

Key-valuecoding支持propertieswithobjectvalues,以及thescalartypes、structs.“Scalar
andStructureSupport”描述了非对象参数及返回类型(Non-objectparametersandreturntypes)的识别及自动包装、自动解包(automaticallywrapped,andunwrapped).

1、Key-ValueCodingandScripting

Cocoa支持脚本(scripting),以便程序通过accessingitsModelobjects,轻松实现scripting,这些Modelobjects封装该程序的数据.当针对自己的程序执行anAppleScriptcommand时,目的是让thatAppleScriptcommand直接进入到程序的Modelobjects中来完成工作(gettheworkdone).

OSX中的scripting严重依赖于key-valuecoding,来提供对executingAppleScriptcommands的自动支持.Inascriptableapplication,amodelobject定义了它支持的asetofkeys.Eachkeyrepresentsapropertyofthemodelobject.一些scripting-relatedkeys的例子有:
words
,
font
,
documents
,
color
.The
key-valuecodingAPI提供了一个通用及自动的方法来queryanobjectforthevaluesofitskeysandtosetnewvaluesforthosekeys.

当设计程序的对象时(designtheobjectsofyourapplication),应当definethesetofkeysforyourmodelobjects,并implementthecorrespondingaccessormethods.然后当定义适合自己程序的脚本时(thenwhendefinethescriptsuitesforyourapplication),可以指定thekeysthateachscriptableclass
supports.当你支持key-valuecoding,你就“免费”得到许多scripting的支持.

InAppleScript,对象层次结构(objecthierarchies)定义了程序中Modelobjects'sstructure.大多数AppleScriptcommands指定了程序中的oneormoreobjects,通过drillingdownthisobjecthierarchyfromparentcontainertothechildelement.你可以通过key-valuecodinginclassdescriptions,定义 the
relationshipbetweenproperties.详情参见Describing
PropertyRelationships.

Cocoa'sscriptingsupport利用key-valuecoding来getandsetinformationinscriptableobjects.Objective-C非正式协议NSScriptKeyValueCoding中的Methods提供了使用key-value
coding的其它功能,包括gettingandsettingkeyvaluesbyindexinmulti-valuekeysandcoercing(converting)akey-valuetotheappropriatedatatype.

2、使用Key-ValueCoding来简化代码(UsingKey-valueCodingtoSimplifyyourcode)

在代码中,可以使用key-valuecodingmethods来概括实现(generalize
implementations).比如,在OSX中,
NSTableView
and
NSOutlineView
objects
都把自己的每列绑定anidentifierstring.通过使thisidentifierstring与希望显示的property相同,可以有效简化代码.

Listing1Implementation
ofNSTableViewdata-sourcemethod
withoutkey-valuecoding

-(id)tableView:(NSTableView*)tableview

objectValueForTableColumn:(id)columnrow:(NSInteger)row{


ChildObject*child=[childrenArrayobjectAtIndex:row];

if([[columnidentifier]isEqualToString:@"name"]){

return[childname];

}

if([[columnidentifier]isEqualToString:@"age"]){

return[childage];

}

if([[columnidentifier]isEqualToString:@"favoriteColor"]){

return[childfavoriteColor];

}

//Andsoon.

}

Listing2ImplementationofNSTableViewdata-sourcemethodwithkey-valuecoding

-(id)tableView:(NSTableView*)tableview

objectValueForTableColumn:(id)columnrow:(NSInteger)row{


ChildObject*child=[childrenArrayobjectAtIndex:row];

return[childvalueForKey:[columnidentifier]];

}

三、术语(Terminology)

除了重载一些现存术语,key-valuecoding也定义了一些自己的专用术语.

Key-valuecoding可以用来访问三种不同类型的对象值(accessthreedifferenttypesofobjectvalues):attributes,to-onerelationships,to-manyrelationships.术语"property"
指的是上述三种类型对象值的任意一种.

Anattribute是一个有一个简单值(asimplevalue)的property,比如:ascalar,string,Booleanvalue.Valueobjects,比如NSNumber及其它不可变的类型如NSColor也被当作
attributes.

Avalueobject实质上是一些简单数据条目(asimpledataelement),比如astring,number,ordate,的面向对象封装.Cocoa中常见的valueclasses有:
NSString
,
NSDate
,
and
NSNumber
.Valueobjects通常是attributesofothercustomobjectsyoucreate.

Ascalartype实质上是一些基本数值类型,比如C语言中的一些基本数值类型:
char
,
NSTimeInterval
,
int
,
float
,
or
double.

/*

NSValue
providesasimplecontainerforasingleCorObjective-Cdataitem.Itcanholdanyofthescalartypessuchas
char
,
int
,
float
,
or
double
,aswellaspointers,structures,andobjectIDs.Itletsyouadditemsofsuchdatatypestocollectionssuchasinstancesof
NSArray
and
NSSet
,
whichrequiretheirelementstobeobjects.Thisisparticularlyusefulifyouneedtoputpoint,size,orrectanglestructures(suchas
NSPoint
,
CGSize
,
or
NSRect
)intoacollection.

*/

一个指定一对一关系的(to-onerelationship)的property是一个对象(object),该对象拥有自己的property.Theseunderlyingpropertiescanchangewithouttheobjectitselfchanging.比如说,anNSViewinstance's
superview就是一种一对一的关系.

一个指定一对多关系的(to-manyrelationship)的property是一个包含相关对象的集合类对象(acollectionofrelatedobjects).通常,aninstanceof
NSArray
or
NSSet

可用来持有这样一个集合.但,key-valuecoding允许使用自定义的collectionclasses,通过实现key-valuecodingaccessors(参见Collection
AccessorPatternsforTo-ManyProperties),访问这些自定义collectionclasses,就像它们是一个
NSArray
or
NSSet

类.

/*

AcollectionisaFoundationframeworkobjectwhoseprimaryroleistostoreobjectsintheformofarrays,dictionaries,andsets.The
primarycollectionclasses—
NSArray
,
NSSet
,
and
NSDictionary
—share
anumberoffeaturesincommon.

*/

四、Key-ValueCoding基本原理(key-valuecodingfundamentals)

以下描述key-valuecoding的基本原则

1、KeysandKeyPaths

Akey是标识一个对象的特定属性的一个字符串(Akeyisastringthatidentifiesaspecificpropertyofanobject).通常,Akey与接收对象(receivingobject)的特定accessor
method'sname或instancevariable一致.Keys必须用ASCII编码,以小写字母开头,且不能包含空格.

典型的Keys的例子有:
payee
,
openingBalance
,
transactions
and
amount

Akeypath是一个点号分隔的keys字符串(astringofdotseparatedkeys),用以指定objectproperties序列.该序列中第一个key标识的property与接收对象关联,且每个后续的key都与之前的property相关联(andeachsubsequentkeyisevaluatedrelativetothevalue
ofthepreviousproperty.).
比如:keypathaddress.street将从接收对象获取addressproperty
的值,然后决定和addressobject关联的streetproperty的值.
2、使用key-valuecoding来获取AttributeValues(GettingAttributeValuesUsingKey-ValueCoding)valueForKey:方法返回与其接收对象关联的某指定key的value.若该指定key没有相应的accessor或instancevariable,则接收对象则会给自己发送一条valueForUndefinedKey:消息.
valueForUndefinedKey:方法的默认实现会抛出一个NSUndefinedKeyException;
子类可以override该方法.
valueForKeyPath:方法返回与其接收对象关联的某指定keypath的value.该keypathsequence中,对于对应的key,任何不兼容key-valuecoding的object都会收到一条valueForUndefinedKey:message
(Anyobjectinthekeypathsequencethatisnotkey-valuecodingcompliantfortheappropriatekeyreceivesa
valueForUndefinedKey:
message).
dictionaryWithValuesForKeys:方法取出与其接收对象关联的anarrayofkeys的valuedictionary.返回的NSDictionary包含valuesforallthekeysin
thearray.
注意:Collectionobjects,比如
NSArray
,
NSSet
,
NSDictionary
,不能包含nil作为自己的元素.可以用NSNullobject
来代表nilvalueforobjectproperties.
dictionaryWithValuesForKeys:
setValuesForKeysWithDictionary: 
这两方法的默认实现会自动转换NSNull及nil,故your
objectsdon’thavetoexplicitlytestfor
NSNull
values.
若某keypath中包含有一个一对多关系的property的key,且该key不是该keypath中的最后一个key,那么该keypath返回的value是一个collectionobject,该collectionobject包含allthevaluesforthekeystotherightoftheto-manykey.比如说,keypathtransactions.payee
的值请求返回一个array,该array包含allthe
payee
objects,forallthetransactions.这对keypath中的multiplearrays同样有效.对于keypathaccounts.transactions.payee将返回一个
array,该array包含allthepayeeobjects,forallthetransactions,inalltheaccounts.
3、使用key-valuecoding来设置AttributeValues(SettingAttributeValuesusingKey-ValueCoding)
setValue:forKey:方法设置与其关联的对象指定key的value为指定的value.setValue:forKey:方法的默认实现自动的解封(unwraps)
NSValueobjects(代表scalars及structs),并把它们指定给相应的property.封闭及解封(wrappingandunwrapping)的详情参见"Scalar
andStructureSupport".

若指定的key不存在,则该方法关联对象将收到一条
setValue:forUndefinedKey:message.setValue:forUndefinedKey:方法的默认实现抛出一个NSUndefinedKeyException异常;子类可以重写(override)该方法来自定义处理该异常.

setValue:forKeyPath:方法以一种相似的方式工作,但它既可以处理keypath,也可以处理asinglekey.
setValuesForKeysWithDictionary:方法
setsthereceiver's
propertieswiththevaluesinthespecifieddictionary,通过该dictionary'skeys来标识thereceiver'sproperties.该方法的默认实现对于每个
key-valuepair,调用
setValue:forKey:方法,需要时,用
NSNullobjects替代
nil.

另外需要考虑的问题是:当尝试setanon-objectpropertytoanilvalue时,会发生什么.这种情况下,thereceiver会给自身发送条setNilValueForKey:message.setNilValueForKey:方法的默认实现会抛出一个NSInvalidArgumentException异常.程序中可以重写该方法来提供一个a
defaultvalueoramarkervalue,然后使用thenewvalue来调用
setValue:forKey:方法.

4、点号语法和key-valuecoding(DotSyntaxandKey-ValueCoding)

Objective-C的dotsyntax和key-valuecoding是正交技术.使用key-valuecoding时,可以使用也可以不使用dotsyntax;使用dotsyntax时,可以使用也可以不使用KVC.Both,though,makeuseofa"dotsyntax".在使用key-valuecoding的情况下,点运算符用来分隔keypath中的元素(delimitelementsinakeypath).记住:当使用dot
syntax来accessaproperty时,实际上是调用thereceiver'sstandard
accessormethods.

/*

Anaccessormethodisaninstancemethodthatgetsorsetsthevalueofapropertyofanobject.InCocoa’sterminology,amethodthatretrievesthevalueofanobject’spropertyisreferredtoasagettermethod,or“getter;”amethodthatchangesthevalue
ofanobject’spropertyisreferredtoasasettermethod,or“setter.”Thesemethodsareoftenfoundinpairs,providingAPIforgettingandsettingthepropertyvaluesofanobject.

Youshoulduseaccessormethodsratherthandirectlyaccessingstatedatabecausetheyprovideanabstractionlayer.Herearejusttwoofthebenefitsthataccessormethodsprovide:

Youdon’tneedtorewriteyourcodeifthemannerinwhichapropertyisrepresentedorstoredchanges.

Accessormethodsoftenimplementimportantbehaviorthatoccurswheneveravalueisretrievedorset.Forexample,settermethodsfrequentlyimplementmemorymanagementcodeandnotifyotherobjectswhenavalueischanged.

*/

可以使用key-valuecodingmethods来accessaproperty.比如,某class定义如下:

@interfaceMyClass

@propertyNSString*stringProperty;

@propertyNSIntegerintegerProperty;

@propertyMyClass*linkedInstance;

@end

可以使用KVC来访问其实例对象的properties如下:

MyClass*myInstance=[[MyClassalloc]init];

NSString*string=[myInstancevalueForKey:@"stringProperty"];

[myInstancesetValue:@2forKey:@"integerProperty"];

为了演示使用dotsyntax语法与KVCkeypaths区别,考虑如下使用:

MyClass*anotherInstance=[[MyClassalloc]init];

myInstance.linkedInstance=anotherInstance;

myInstance.linkedInstance.integerProperty=2;

下面使用方法和上述结果一样:

MyClass*anotherInstance=[[MyClassalloc]init];

myInstance.linkedInstance=anotherInstance;

[myInstancesetValue:@2forKeyPath:@"linkedInstance.integerProperty"];

五、Key-ValueCodingAccessorMethods

为了使key-valuecoding定位theaccessormethods以便调用
valueForKey:
,
setValue:forKey:
,
mutableArrayValueForKey:
,
mutableSetValueForKey:
这些方法,需要实现
thekey-valuecodingaccessormethods.

提示:本小节中所述的theaccessorpatterns是用
-set<Key>:
-<key>
形式写的
The<key>text
isaplaceholderforthenameofyourproperty.
相应方法的实现应当根据key指定的情况,用thepropertyname来替换<Key>或<key>.例如:对于某
propertyname,
-set<Key>:
应当扩展为
-setName:
,
-<key>
则简单的为
-name
.

1、常用的Accessorpatterns(CommonlyUsedAccessorPatterns)

Anaccessormethodthatreturnsaproperty的形式是-<key>.该

-<key>方法returnsanobject,scalar,oradatastructure.另一种命名形式
-is<Key>被用以返回Booleanproperties.

Listing1Accessor
namingvariationsfora
hiddenpropertykey

-(BOOL)hidden{

//Implementationspecificcode.

return...;

}

Listing
2Alternateformaccessorfora

hiddenpropertykey

-(BOOL)isHidden{

//Implementationspecificcode.

return...;

}

为使某attribute或某to-onerelationshipproperty支持
setValue:forKey,必须实现一个
set<Key>:形式的accessor.

Listing3Accessor
namingconventiontosupportahiddenproperty
key

-(void)setHidden:(BOOL)flag{

//Implementationspecificcode.

return;

}

若某attributeisanon-objecttype,则,用一个
nilvalue来设定其值时,必须合适的处理.当试图setanattributeto
nil时,setNilValueForKey:方法会被调用
.这样就有机会提供appropriatedefaultvaluesforyourapplication,或
handlekeysthatdon’thavecorrespondingaccessorsintheclass.

下例演示,当试图setthe
hiddenattributeto
nil时,默认setitto
YES.示例中,Itcreatesan

NSNumberinstancecontainingtheBooleanvalue,thenuses
setValue:forKey:tosetthenewvalue.这样保持了encapsulationofthemodel,且确保由于settingthevalue而可能产生的anyadditionalactions实实在在的执行(actuallyoccur).这样被认为是比callinganaccessormethod或settinganinstancevariabledirectly更好的作法.

-(void)setNilValueForKey:(NSString*)theKey{


if([theKeyisEqualToString:@"hidden"]){

[selfsetValue:@YESforKey:@"hidden"];

}

else{

[supersetNilValueForKey:theKey];

}

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: