我想了解如何设置属性(访问者)的参数。
我从Kal日历的例子中获取了以下代码。
// Holiday.h
@interface Holiday : NSObject
{
NSDate *date;
NSString *name;
NSString *country;
}
@property (nonatomic, retain, readonly) NSDate *date;
@property (nonatomic, retain, readonly) NSString *name;
@property (nonatomic, retain, readonly) NSString *country;
- (id)initWithName:(NSString *)name country:(NSString *)country date:(NSDate *)date;
@end
// Holiday.m
#import "Holiday.h"
@implementation Holiday
@synthesize date, name, country;
- (id)initWithName:(NSString *)aName country:(NSString *)aCountry date:(NSDate *)aDate
{
if ((self = [super init])) {
name = [aName copy];
country = [aCountry copy];
date = [aDate retain];
}
return self;
}
- (void)dealloc
{
[date release];
[name release];
[country release];
[super dealloc];
}
@end
1)属性设置为retain
,但由于无法使用setter,retain
在这里没有任何意义。
2)此外,在initWithName
方法中,值设置为copy
。为什么不直接使用copy
定义属性并使用访问器方法?
@property (nonatomic, copy) NSString *name;
// ...
self.name = aName;
3)我需要readonly
吗?我不知道他们为什么在这里使用。如果我将copy
与setter一起使用readonly
禁止我设置值,因为没有setter。
4)在initWithName
方法中,有时使用copy
,有时使用retain
。我建议在这里始终使用copy
,因为以后不应修改该值。
5)我记得的是,copy
中的retain
/ initWithName
和release
方法中的dealloc
是可以的。
那么您如何建议在此示例中使用retain
,copy
和readonly
?
答案 0 :(得分:13)
ETA: @DougW正确指出某个媒体资源的所有权类型(assign
/ retain
/ copy
)没有影响吸气剂。它仍然会影响二传手。对于readonly
类型,如果您要在类扩展中覆盖声明的readonly
部分,这很重要,因此您可以在实现中使用setter。类扩展属性覆盖只允许更改属性的readonly
状态,因此必须在标头中正确声明其余部分(即原子性和所有权类型)。即使您现在没有覆盖该属性,也可能在将来使用,因此您可以使用正确的选项开始记录您希望如何管理内存。
自动引用计数(ARC)通过在经典引用计数规则之上叠加自己的内存管理规则来更改运行时实现细节,但配置属性的规则和建议保持不变。
为什么将retain
与readonly
一起使用?如果您将属性标记为retain
,则合成访问者会执行以下操作:
/* getter for retain property */
- (NSString *)name {
return [[name retain] autorelease];
}
现在,如果您发送的对象-name
在您仍在使用时更改了名称,则调用代码仍将具有对字符串的有效引用。但是,如果您将其声明为assign
,则可能是这样的:
/* getter for assign property */
- (NSString *)name {
return name;
}
现在,只要对象更改了名称,就必须释放它以避免泄漏,这将使调用代码的引用无效。 retain
/ copy
/ assign
实际上是在说明内存管理政策:retain
/ copy
说:“我保证我会提及我在这里提供的原始/我的价值副本,“虽然assign
说,”我只是拥有价值,并声称没有自己的参考。“
当值不需要内存管理时,例如普通int
,那么assign
是有意义的。如果您故意不保留对象(例如委托),那么assign
就有意义了。但是,在大多数其他情况下,您需要retain
或copy
。
此外,实现文件只能覆盖属性声明的readwrite
/ readonly
部分,而不是内存管理部分。如声明的那样,.m
文件可以包含:
@interface Holiday (/*class extension*/)
@property(nonatomic, retain, readwrite) NSDate *date;
/* override other properties to make them readwrite... */
@end
覆盖的属性声明的非公共setter将与公共访问器一起合成。
为什么不在-init
期间使用setter / accessors?因为setter / accessors经常执行KVO通知,您希望在对象未完全初始化时避免,即在{{ 1}}(当它在完全初始化的路上被半初始化时)和-init
(当它在完全未初始化的路上被半初始化时)。
为什么将-dealloc
与copy
一起使用?在回答您的第一个问题时:因为readonly
与copy
对{{1}影响setter和getter。复制getter看起来像这样:
retain
为什么有时assign
,有时/* getter for copy property */
- (NSString *)name {
return [[name copy] autorelease];
}
? copy
通常与值对象(表示值的被动对象)一起使用; retain
通常与其他对象一起使用。有时候,效率问题会发挥作用(很可能过早地......),您可能会选择使用copy
通常使用retain
的地方。
你如何在这里使用retain
/ copy
以及copy
?就像他们一样。我会覆盖类扩展中的声明,因此我可以使用setter来更改retain
和readonly
之外的属性值,其中我只使用直接实例变量访问。在-init
中释放它们之后,我也会-dealloc
出来,例如,
nil
这有助于避免向已发布的对象发送消息或以其他方式引用已发布的对象。