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

Objective-C 编程语言官网文档(五)-属性的声明

2012-06-04 18:22 435 查看


声明:本文档仅为个人学习过程中顺手翻译之作,方便开发的同胞借鉴参考。如有觉得译的不好不到位的地方,欢迎指正,将及时做出更正

尽量尊重原文档,因为首次Objective-C,有些地方可能直译了没有注意该语言的专有词,希望指正。如需转载,请注明出处



我的编程环境:

IDE:XCODE4.3.1

OS:MACOSX10.7.4

文章来译自:http://developer.apple.com/


属性声明

Objective-C声明属性特性提供了一个简单的方式来声明以及实现一个变量访问其方法。


概述

通常你会通过一对访问器方法(getter/setter)来访问对象的属性(inthesenseofitsattributesandrelationships)。通过使用访问器方法,你很好的遵循了封装的原则(可以参考Object-Oriented
ProgrammingwithObjective-C中的“Mechanisms
OfAbstraction”)。当API的客户端与实现的改变保持隔离时,你可以有效的控制getter/setter方法的以及对基本状态管理的行为。
尽管使用访问器方法显然有着重要的好处,但写这些访问器方法无疑是件枯燥的活儿。除此之外,对于API的使用者很重要的属性方面变的含混不清—例如是否访问器方法是线程安全的或者当设值时是否新值被复制。
声明的属性通过提供以下特性来解决上述问题:

属性声明为访问器方法的行为提供了清晰,显式的配置。

编译器可以按照你在声明中的配置为你合成访问器方法。

属性语法上表示标示符,加上作用域限制,因此,编译器可以检测到未声明的属性的使用。


属性声明以及实现

声明的属性包含两个部分,声明以及实现。


属性声明

属性声明以关键词
@property
开头。
@property
可以出现在类的
@interface
块中方法声明的任何地方。
@property
还可以出现在protocol或者category声明中。

@property(attributes)typename;

@property
指令声明了一个属性。括号内的可选参数提供了有关语义存储以及其它行为的额外细节—可用值可以参考“Property
DeclarationAttributes”。像其它的Objective-C类型,每个属性都有类型配置和名字。
4-1展示了一个简单的属性声明

4-1

@interfaceMyClass:NSObject

@propertyfloatvalue;

@end

你可以把一个属性声明等价于两个访问器方法。

@propertyfloatvalue;

等价于

-(float)value;

-(void)setValue:(float)newValue;

然而,一个属性声明还可以提供有关访问器方法如何实现的额外信息。(就像“Property
DeclarationAttributes”中描述的那样).
你也可以把属性声明放在类扩展中(参见“Extensions”).
例如,你可以把之前看到过的
value
属性声明如下:

@interfaceMyClass:NSObject

@end


@interfaceMyClass()

@propertyfloatvalue;

@end

要是你向隐藏私有属性的声明的话,上面的方法将会很有用。


属性(Property)声明中的额外属性(Attribute)

Property跟Attribute都可翻译为属性,但两者在这里是不同的,Property只类范围的属性,而Attributes是额外属性,作用域比Property小。为避免混淆,额外属性指代Attribute,如果没有加额外二字,则默认指Property。通过
@property(attribute
[,attribute2,...])
可以使用带有额外属性的属性。像方法一样,属性作用域限定在它们的包装借口声明中。属性使用逗号来分隔一系列变量名,属性的额外属性会应用于所有的命名属性。
如果你使用
@synthesize
指令来告诉编译器去创建访问器方法(参见“Property
ImplementationDirectives”),自动生成的代码与所给的关键词是匹配的。如果你自己来实现访问器方法,你应当确保访问器方法与配置相匹配(例如,要是你指定了
copy
,你就要确保你确实将输入值拷贝到了setter方法).


访问器方法名

默认与属性相关的getter和setter方法是这样的形式:propertyName和
set
PropertyName,例如,有个属性叫
“foo”,访问器则应当是
foo
setFoo:
.
下面的结构则允许我们指定个性化的名字来取代上面的默认形式。它们都是可选的,可以出现在任何其它额外属性中(除了setter=中的
readonly
).

getter=getterName

指定属性的get访问器名。getter返回值类型必须符合属性类型并且getter方法中不能有任何参数。
setter=setterName

指定属性的set访问器名。setter方法必须带有一个与属性类型一样类型的参数,并且返回值类型为
void
.
假如你指定了一个属性为
readonly
并且用
setter=
指定了一个
setter方法,编译器就会给出警告。

通常你指定的访问器方法名应当符合键值编码标准(参考Key-Value
CodingProgrammingGuide)—通常我们使用
getter
修饰器的原因是为了遵循布尔值的属性命名约定.


可写性

这些额外属性指定了是否一个属性与set访问器关联了。这些选项是互斥的。

readwrite

知名属性属性是read/write.默认是这个选项。
getter跟setter方法都要放在
@implementation
块中.要是你在实现块中使用
@synthesize
指令,
getter和setter方法则将被集成。
readonly

指明属性是只读的。
如果你指定了
readonly
,那么
@implementation
块中只需要一个getter方法.要是你在实现块中使用
@synthesize
指令,
那么只有getter方法会被集成。除此之外,假设你试图使用逗点语法给一个只读属性赋值,编译器将会报错。


Setter语法

这些额外属性指明了set访问器的语法。这些选项是互斥的。

strong

指明此属性跟目标对象有着紧密的(拥有)关系。
weak

指明与目标对象是松散的(非拥有)关系。
假如目标对象被释放了,属性值将自动被设为
nil
.
(OSXv10.6和iOS4不支持弱属性;取而代之的是
assign
.)
copy

指明对象的副本应当用于赋值操作。
之前的值发送给一个
release
消息.
副本通过调用
copy
方法被创建.
除了对象类型(实现了
NSCopying
协议),对其它类型这个额外属性是无效的。
assign

指明setter使用简单赋值。这个额外属性是默认选项。
在标量类型中你会用到这个额外属性,例如
NSInteger
CGRect
.
retain

指明对象赋值时执行
retain

之前的值将发给一个
release
消息。
在OSXv10.6以及更新的版本中,你可以使用
__attribute__
关键字来指定一个CoreFoundation属性应当被当做一个用于内存管理的Objective-C对象对待。

@property(retain)__attribute__((NSObject))CFDictionaryRefmyDictionary;


原子性

你可以使用这个额外属性来指明访问器方法是非原子的。(没有关键词可以表示原子的)

nonatomic

指明访问器是非原子的。默认情况下,访问器是原子的。

属性默认是原子的,这种情况下生成的访问器提供了多线程环境下对属性的安全访问/存取互斥互斥,同一时刻,只有一个线程可以访问属性。
要是你指定了
strong
,
copy
或者
retain
并且没有指定
nonatomic
那么在一个引用计数环境中,为属性生成的get访问器将使用lock,
retain,自动释放返回的值,然后才返回结果。实现与下面的代码类似:

[_internallock];//lockusinganobject-levellock

idresult=[[valueretain]autorelease];

[_internalunlock];

returnresult;

要是指定了
nonatomic
,该对象属性生成的访问器会直接返回值。


标记和弃用

属性支持所有C形式的修饰符。属性可以被启用并支持
__attribute__
风格的标记:

@propertyCGFloatx

***AILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;

@propertyCGFloaty__attribute__((...));

如果你向指定某个属性为一个outlet(参考outletiniOS,以及outletin
OSX),你可以使用
IBOutlet
标示符:

@property(nonatomic,weak)IBOutletNSButton*myButton;

尽管IBOutlet
不是这些额外属性列表中的正式成员。更多有关声明outlet属性的信息,可以参见“Nib
Files”.


属性的实现指令

你可以在
@implementation
块中使用
@synthesize
@dynamic
指令来触发特定的编译器动作。这些对
@property
声明的属性都是可选的。

[b]注意
如果你没有为一个特定的属性指定
@synthesize
或者
@dynamic
,那么你就必须提供属性的
getter及setter方法实现(或者在
readonly
情况下提供getter),否则,编译器就会给出一个警告。

@synthesize

你可以使用
@synthesize
指令来告诉编译器,要是你没有在
@implementation
块中提供setter/getter方法,则它应当为一个该属性生成它们。
@synthesize
指令还可以为它生成一个实例变量。

Listing4-2使用@synthesize

@interfaceMyClass:NSObject

@property(copy,readwrite)NSString*value;

@end


@implementationMyClass

@synthesizevalue;

@end

你可以使用
property=ivar
的形式来为一个属性指定一个特定的实例变量,例如

@synthesizefirstName,lastName,age=yearsOld;

生成方法的其它方面决定于其它可选的额外属性。(参见“Property
DeclarationAttributes”).
你指定的实例变量的名字,
@synthesize
指令只能使用来自当前类的实例变量,而不是父类中的。
访问器方法的生成行为可能因运行时环境而异(可以参考“Runtime
Difference”):

对于legacy运行时环境,实例变量必须已经声明在当前类的
@interface
块中了.如果有跟属性同名的一个实例变量存在,并且类型也与属性类型一致,它将被使用,否则,你将看到一个编译器错误。

而对于modern运行时(参考Objective-C
RuntimeProgrammingGuide中的“Runtime
VersionsandPlatforms”),实例变量将按需生成。如果一个同名实例变量存在,它将被使用。

@dynamic

你可以使用
@dynamic
关键字来告诉编译器,属性的获取与赋值方法由用户自己实现,不自动生成,不在这个类中,可能在父类或者别的地方。只有在你确信运行时这些访问器方法将可用时才使用这个关键字。
例如:

4-3

@interfaceMyClass:NSManagedObject

@property(nonatomic,retain)NSString*value;

@end


@implementationMyClass

@dynamicvalue;

@end

NSManagedObject
是由CoreData框架提供的,一个托管的对象类有它自己相应的架构,定义有类的属性及关系。运行时,CoreData框架会为它们按需生成访问器方法。


使用属性


支持类型

你可以为任何Objective-C类声明属性,CoreFoundation数据类型,或者“plainolddata”(POD)类型(参见C++
LanguageNote:PODTypes).使用CoreFoundation类型的约束,可以参看“Core
Foundation.”


属性的重定义

你可以在子类中对一个属性进行重定义,但是(withtheexceptionof
readonly
versus
readwrite
)
你必须在子类中同样重复它的所有额外属性。对于类别或者协议中的属性也是一样的—当属性可能在类别或者协议中被重定义式,属性的所有额外属性也要被完整重复。
如果你在一个类中声明了一个
readonly
属性,你可以在一个类扩展(参见“Extensions”)/
协议或者子类中
(参见“Subclassing
withProperties”)中把它声明为
readwrite
。重声明一个只读属性的能力使两种常见的实现模式成为可能:一个不可变父类的可变的子类(例如
NSString,
NSArray
,
NSDictionary
)以及一个作用域声明为public的只读属性有着一个作用域为私有的可读写的属性实现。例如:

//publicheaderfile

@interfaceMyObject:NSObject

@property(readonly,copy)NSString*language;

@end


//privateimplementationfile

@interfaceMyObject()

@property(readwrite,copy)NSString*language;

@end


@implementationMyObject

@synthesizelanguage;

@end


CoreFoundation

就像在“Property
DeclarationAttributes,”一节中提到的,MacOSXv10.6之前不能为非对象类型指定
retain
额外属性。假设,你要声明一个类型为CFT的属性,并且像下面的例子中这样自动生成访问器。

@interfaceMyClass:NSObject

@property(readwrite)CGImageRefmyImage;

@end


@implementationMyClass

@synthesizemyImage;

@end

在引用计数环境中,自动生成的set访问器简单的为实例变量赋予了一个新值(新值没有保持而旧值没有释放).对于CoreFoundation对象来说,简单赋值通常是错误的。你不应该自动生成这些方法,而是你自己来实现。


属性子类化

你可以重写一个
readonly
属性,并用可写来替换它。例如,下面定义了一个类
MyInteger
,它有一个只读的属性
value
:

@interfaceMyInteger:NSObject

@property(readonly)NSIntegervalue;

@end


@implementationMyInteger

@synthesizevalue;

@end

然后你实现了一个子类,
MyMutableInteger
,它重定义了这个属性并把它设为可写

@interfaceMyMutableInteger:MyInteger

@property(readwrite)NSIntegervalue;

@end


@implementationMyMutableInteger

@dynamicvalue;


-(void)setValue:(NSInteger)newX{

value=newX;

}

@end


运行时差异

一般情况下属性在modern和legacy运行时环境下的行为是一致的(参见Objective-C
RuntimeProgrammingGuide中的“Runtime
VersionsandPlatforms”)。有个关键的区别是,modern运行时支持实例变量的访问器方法自动生成而legacy运行时不支持。
要让
@synthesize
在legacy运行时能够工作,你就必须提供一个跟该属性有相同名字以及类型的实例变量或者指定另外一个已经存在于
@synthesize
块中的实例变量。在
modern运行时下,如果你不提供实例变量,编译器会为你自动添加一个。例如,

@interfaceMyClass:NSObject

@propertyfloatnoDeclaredIvar;

@end


@implementationMyClass

@synthesizenoDeclaredIvar;

@end

在legacy运行时下会在
@synthesizenoDeclaredIvar
处报错,而在modern运行时下,编译器会添加一个实例变量来代替
noDeclaredIvar
.

英文原文:

点击打开链接


DeclaredProperties

TheObjective-Cdeclaredpropertiesfeatureprovidesasimplewaytodeclareandimplementanobject’saccessormethods.


Overview

Youtypicallyaccessanobject’sproperties(inthesenseofitsattributesandrelationships)throughapairofaccessor(getter/setter)methods.Byusingaccessormethods,youadheretotheprincipleofencapsulation(see“Mechanisms
OfAbstraction”inObject-Oriented
ProgrammingwithObjective-C).Youcanexercisetightcontrolofthebehaviorofthegetter/setterpairandtheunderlyingstatemanagementwhileclientsoftheAPIremaininsulatedfromtheimplementationchanges.
Althoughusingaccessormethodsthereforehassignificantadvantages,writingaccessormethodsisatediousprocess.Moreover,aspectsofthepropertythatmaybeimportanttoconsumersoftheAPIareleftobscured—such
aswhethertheaccessormethodsarethread-safeorwhethernewvaluesarecopiedwhenset.
Declaredpropertiesaddresstheseissuesbyprovidingthefollowingfeatures:

Thepropertydeclarationprovidesaclear,explicitspecificationofhowtheaccessormethodsbehave.

Thecompilercansynthesizeaccessormethodsforyou,accordingtothespecificationyouprovideinthedeclaration.

Propertiesarerepresentedsyntacticallyasidentifiersandarescoped,sothecompilercandetectuseofundeclaredproperties.


PropertyDeclarationandImplementation

Therearetwopartstoadeclaredproperty,itsdeclarationanditsimplementation.


PropertyDeclaration

Apropertydeclarationbeginswiththekeyword
@property
.
@property
can
appearanywhereinthemethoddeclarationlistfoundinthe
@interface
blockofaclass.
@property
can
alsoappearinthedeclarationofaprotocolorcategory.

@property(attributes)typename;

The
@property
directivedeclaresaproperty.Anoptionalparenthesizedsetofattributesprovidesadditionaldetailsaboutthe
storagesemanticsandotherbehaviorsoftheproperty—see“Property
DeclarationAttributes”forpossiblevalues.LikeanyotherObjective-Ctype,eachpropertyhasatypespecificationandaname.
Listing4-1illustratesthedeclarationofasimpleproperty.

Listing4-1Declaringasimpleproperty

@interfaceMyClass:NSObject

@propertyfloatvalue;

@end

Youcanthinkofapropertydeclarationasbeingequivalenttodeclaringtwoaccessormethods.Thus

@propertyfloatvalue;

isequivalentto:

-(float)value;

-(void)setValue:(float)newValue;

Apropertydeclaration,however,providesadditionalinformationabouthowtheaccessormethodsareimplemented(asdescribedin“Property
DeclarationAttributes”).
Youcanalsoputpropertydeclarationsinclassextensions(see“Extensions”).
Forexample,youcoulddeclarethe
value
propertyshownpreviouslyasfollows:

@interfaceMyClass:NSObject

@end


@interfaceMyClass()

@propertyfloatvalue;

@end

Thisisusefulifyouwanttohidethedeclarationofprivateproperties.


PropertyDeclarationAttributes

Youcandecorateapropertywithattributesbyusingtheform
@property(attribute[,attribute2,...])
.Likemethods,properties
arescopedtotheirenclosinginterfacedeclaration.Forpropertydeclarationsthatuseacomma-delimitedlistofvariablenames,thepropertyattributesapplytoallofthenamedproperties.
Ifyouusethe
@synthesize
directivetotellthecompilertocreatetheaccessormethods(see“Property
ImplementationDirectives”),thecodeitgeneratesmatchesthespecificationgivenbythekeywords.Ifyouimplementtheaccessormethodsyourself,youshouldensurethatitmatchesthespecification(forexample,ifyouspecify
copy
you
mustmakesurethatyoudocopytheinputvalueinthesettermethod).


AccessorMethodNames

ThedefaultnamesforthegetterandsettermethodsassociatedwithapropertyarepropertyNameand
set
PropertyName
:
respectively—for
example,givenaproperty“foo”,theaccessorswouldbe
foo
and
setFoo:
.Thefollowingattributes
allowyoutospecifycustomnamesinstead.Theyarebothoptionalandcanappearwithanyotherattribute(exceptfor
readonly
inthecaseof
setter=
).

getter=getterName

Specifiesthenameofthegetaccessorfortheproperty.Thegettermustreturnatypematchingtheproperty’stypeandtakenoparameters.
setter=setterName

Specifiesthenameofthesetaccessorfortheproperty.Thesettermethodmusttakeasingleparameterofatypematchingtheproperty’stypeandmustreturn
void
.
Ifyouspecifythatapropertyis
readonly
andalsospecifyasetterwith
setter=
,
yougetacompilerwarning.

Typicallyyoushouldspecifyaccessormethodnamesthatarekey-valuecodingcompliant(seeKey-Value
CodingProgrammingGuide)—acommonreasonforusingthe
getter
decoratoristoadheretothe
is
PropertyNameconvention
forBooleanvalues.


Writability

Theseattributesspecifywhetherornotapropertyhasanassociatedsetaccessor.Theyaremutuallyexclusive.

readwrite

Indicatesthatthepropertyshouldbetreatedasread/write.Thisattributeisthedefault.
Bothagetterandsettermethodarerequiredinthe
@implementation
block.Ifyouusethe
@synthesize
directive
intheimplementationblock,thegetterandsettermethodsaresynthesized.
readonly

Indicatesthatthepropertyisread-only.
Ifyouspecify
readonly
,onlyagettermethodisrequiredinthe
@implementation
block.
Ifyouusethe
@synthesize
directiveintheimplementationblock,onlythegettermethodissynthesized.Moreover,ifyouattempttoassignavalueusingthedotsyntax,you
getacompilererror.


SetterSemantics

Theseattributesspecifythesemanticsofasetaccessor.Theyaremutuallyexclusive.

strong

Specifiesthatthereisastrong(owning)relationshiptothedestinationobject.
weak

Specifiesthatthereisaweak(non-owning)relationshiptothedestinationobject.
Ifthedestinationobjectisdeallocated,thepropertyvalueisautomaticallysetto
nil
.
(WeakpropertiesarenotsupportedonOSXv10.6andiOS4;use
assign
instead.)
copy

Specifiesthatacopyoftheobjectshouldbeusedforassignment.
Thepreviousvalueissenta
release
message.
Thecopyismadebyinvokingthe
copy
method.
Thisattributeisvalidonlyforobjecttypes,whichmustimplementthe
NSCopying
protocol.
assign

Specifiesthatthesetterusessimpleassignment.Thisattributeisthedefault.
Youusethisattributeforscalartypessuchas
NSInteger
and
CGRect
.
retain

Specifiesthat
retain
should
beinvokedontheobjectuponassignment.
Thepreviousvalueissenta
release
message.
InOSXv10.6andlater,youcanusethe
__attribute__
keywordtospecifythataCoreFoundationpropertyshouldbetreated
likeanObjective-Cobjectformemorymanagement:

@property(retain)__attribute__((NSObject))CFDictionaryRefmyDictionary;


Atomicity

Youcanusethisattributetospecifythataccessormethodsarenotatomic.(Thereisnokeywordtodenoteatomic.)

nonatomic

Specifiesthataccessorsarenonatomic.Bydefault,accessorsareatomic.

Propertiesareatomicbydefaultsothatsynthesizedaccessorsproviderobustaccesstopropertiesinamultithreadedenvironment—thatis,thevaluereturnedfromthegetterorsetviathesetterisalwaysfully
retrievedorsetregardlessofwhatotherthreadsareexecutingconcurrently.
Ifyouspecify
strong
,
copy
,or
retain
and
donotspecify
nonatomic
,theninareference-countedenvironment,asynthesizedgetaccessorforanobjectpropertyusesalockandretainsandautoreleasesthereturnedvalue—the
implementationwillbesimilartothefollowing:

[_internallock];//lockusinganobject-levellock

idresult=[[valueretain]autorelease];

[_internalunlock];

returnresult;

Ifyouspecify
nonatomic
,asynthesizedaccessorforanobjectpropertysimplyreturnsthevaluedirectly.


MarkupandDeprecation

PropertiessupportthefullrangeofC-styledecorators.Propertiescanbedeprecatedandsupport
__attribute__
stylemarkup:

@propertyCGFloatx

***AILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;

@propertyCGFloaty__attribute__((...));

Ifyouwanttospecifythatapropertyisanoutlet(seeoutletiniOS,andoutletin
OSX),youusethe
IBOutlet
identifier:

@property(nonatomic,weak)IBOutletNSButton*myButton;

IBOutlet
isnot,though,aformalpartofthelistofattributes.Formoreaboutdeclaringoutletproperties,see“Nib
Files”.


PropertyImplementationDirectives

Youcanusethe
@synthesize
and
@dynamic
directives
in
@implementation
blockstotriggerspecificcompileractions.Notethatneitherisrequiredforanygiven
@property
declaration.

ImportantIfyoudonotspecifyeither
@synthesize
or
@dynamic
for
aparticularproperty,youmustprovideagetterandsetter(orjustagetterinthecaseofa
readonly
property)methodimplementationforthatproperty.Ifyoudonot,the
compilergeneratesawarning.

@synthesize

Youusethe
@synthesize
directivetotellthecompilerthatitshouldsynthesizethesetterand/orgettermethodsforaproperty
ifyoudonotsupplythemwithinthe
@implementation
block.The
@synthesize
directivealso
synthesizesanappropriateinstancevariableifitisnototherwisedeclared.

Listing4-2Using@synthesize

@interfaceMyClass:NSObject

@property(copy,readwrite)NSString*value;

@end


@implementationMyClass

@synthesizevalue;

@end

Youcanusetheform
property=ivar
toindicatethataparticularinstancevariableshouldbeusedfortheproperty,forexample:

@synthesizefirstName,lastName,age=yearsOld;

Thisspecifiesthattheaccessormethodsfor
firstName
,
lastName
,
and
age
shouldbesynthesizedandthattheproperty
age
isrepresentedbytheinstancevariable
yearsOld
.
Otheraspectsofthesynthesizedmethodsaredeterminedbytheoptionalattributes(see“Property
DeclarationAttributes”).
Whetherornotyouspecifythenameoftheinstancevariable,the
@synthesize
directivecanuseaninstancevariableonly
fromthecurrentclass,notasuperclass.
Therearedifferencesinthebehaviorofaccessorsynthesisthatdependontheruntime(seealso“Runtime
Difference”):

Forthelegacyruntimes,instancevariablesmustalreadybedeclaredinthe
@interface
blockofthecurrent
class.Ifaninstancevariableofthesamenameasthepropertyexists,andifitstypeiscompatiblewiththeproperty’stype,itisused—otherwise,yougetacompilererror.

Forthemodernruntimes(see“Runtime
VersionsandPlatforms”inObjective-C
RuntimeProgrammingGuide),instancevariablesaresynthesizedasneeded.Ifaninstancevariableofthesamenamealreadyexists,itisused.

@dynamic

Youusethe
@dynamic
keywordtotellthecompilerthatyouwillfulfilltheAPIcontractimpliedbyapropertyeitherby
providingmethodimplementationsdirectlyoratruntimeusingothermechanismssuchasdynamicloadingofcodeordynamicmethodresolution.Itsuppressesthewarningsthatthecompilerwouldotherwisegenerateifitcan’tfindsuitableimplementations.You
shoulduseitonlyifyouknowthatthemethodswillbeavailableatruntime.
TheexampleshowninListing4-3illustratesusing
@dynamic
with
asubclassof
NSManagedObject
.

Listing4-3Using@dynamicwithNSManagedObject

@interfaceMyClass:NSManagedObject

@property(nonatomic,retain)NSString*value;

@end


@implementationMyClass

@dynamicvalue;

@end

NSManagedObject
isprovidedbytheCoreDataframework.Amanagedobjectclasshasacorrespondingschemathatdefinesattributes
andrelationshipsfortheclass;atruntime,theCoreDataframeworkgeneratesaccessormethodsfortheseasnecessary.Youthereforetypicallydeclarepropertiesfortheattributesandrelationships,butyoudon’thavetoimplementtheaccessormethodsyourself
andshouldn’taskthecompilertodoso.Ifyoujustdeclaredthepropertywithoutprovidinganyimplementation,however,thecompilerwouldgenerateawarning.Using
@dynamic
suppresses
thewarning.


UsingProperties


SupportedTypes

YoucandeclareapropertyforanyObjective-Cclass,CoreFoundationdatatype,or“plainolddata”(POD)type(seeC++
LanguageNote:PODTypes).ForconstraintsonusingCoreFoundationtypes,however,see“Core
Foundation.”


PropertyRedeclaration

Youcanredeclareapropertyinasubclass,but(withtheexceptionof
readonly
versus
readwrite
)
youmustrepeatitsattributesinwholeinthesubclasses.Thesameholdstrueforapropertydeclaredinacategoryorprotocol—whilethepropertymayberedeclaredinacategoryorprotocol,the
property’sattributesmustberepeatedinwhole.
Ifyoudeclareapropertyinoneclassas
readonly
,youcanredeclareitas
readwrite
in
aclassextension(see“Extensions”),
inaprotocol,orinasubclass(see“Subclassing
withProperties”).Inthecaseofaclassextensionredeclaration,thefactthatthepropertywasredeclaredpriortoany
@synthesize
statementcausesthesetter
tobesynthesized.Theabilitytoredeclarearead-onlypropertyasread/writeenablestwocommonimplementationpatterns:amutablesubclassofanimmutableclass(
NSString
,
NSArray
,
and
NSDictionary
areallexamples)andapropertythathasapublicAPIthatis
readonly
but
aprivate
readwrite
implementationinternaltotheclass.Thefollowingexampleshowsusingaclassextensiontoprovideapropertythatisdeclaredasread-onlyinthepublic
headerbutisredeclaredprivatelyasread/write.

//publicheaderfile

@interfaceMyObject:NSObject

@property(readonly,copy)NSString*language;

@end


//privateimplementationfile

@interfaceMyObject()

@property(readwrite,copy)NSString*language;

@end


@implementationMyObject

@synthesizelanguage;

@end


CoreFoundation

Asnotedin“Property
DeclarationAttributes,”priortoMacOSXv10.6youcannotspecifythe
retain
attributefornon-objecttypes.If,therefore,youdeclareapropertywhosetypeis
aCFTypeandsynthesizetheaccessorsasillustratedinthefollowingexample:

@interfaceMyClass:NSObject

@property(readwrite)CGImageRefmyImage;

@end


@implementationMyClass

@synthesizemyImage;

@end

theninareference-countedenvironment,thesynthesizedsetaccessorsimplyassignsthenewvaluetotheinstancevariable(thenewvalueisnotretainedandtheoldvalueisnotreleased).Simpleassignment
istypicallyincorrectforCoreFoundationobjects;youshouldnotsynthesizethemethodsbutratherimplementthemyourself.


SubclassingwithProperties

Youcanoverridea
readonly
propertytomakeitwritable.Forexample,youcoulddefineaclass
MyInteger
with
a
readonly
property,
value
:

@interfaceMyInteger:NSObject

@property(readonly)NSIntegervalue;

@end


@implementationMyInteger

@synthesizevalue;

@end

Youcouldthenimplementasubclass,
MyMutableInteger
,whichredefinesthepropertytomakeitwritable:

@interfaceMyMutableInteger:MyInteger

@property(readwrite)NSIntegervalue;

@end


@implementationMyMutableInteger

@dynamicvalue;


-(void)setValue:(NSInteger)newX{

value=newX;

}

@end


RuntimeDifference

Ingeneralthebehaviorofpropertiesisidenticalonbothmodernandlegacyruntimes(see“Runtime
VersionsandPlatforms”inObjective-C
RuntimeProgrammingGuide).Thereisonekeydifference:themodernruntimesupportsinstancevariablesynthesiswhereasthelegacyruntimedoesnot.
For
@synthesize
toworkinthelegacyruntime,youmusteitherprovideaninstancevariablewiththesamenameandcompatible
typeofthepropertyorspecifyanotherexistinginstancevariableinthe
@synthesize
statement.Withthemodernruntime,ifyoudonotprovideaninstancevariable,thecompiler
addsoneforyou.Forexample,giventhefollowingclassdeclarationandimplementation:

@interfaceMyClass:NSObject

@propertyfloatnoDeclaredIvar;

@end


@implementationMyClass

@synthesizenoDeclaredIvar;

@end

thecompilerforthelegacyruntimewouldgenerateanerrorat
@synthesizenoDeclaredIvar;
whereasthecompilerforthemodern
runtimewouldaddaninstancevariabletorepresent
noDeclaredIvar
.

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