初始化器,属性,访问器和复制/保留/只读

时间:2010-10-28 15:02:32

标签: iphone objective-c properties initialization accessor

我想了解如何设置属性(访问者)的参数。

我从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 / initWithNamerelease方法中的dealloc是可以的。

那么您如何建议在此示例中使用retaincopyreadonly

1 个答案:

答案 0 :(得分:13)

ETA: @DougW正确指出某个媒体资源的所有权类型(assign / retain / copy)没有影响吸气剂。它仍然会影响二传手。对于readonly类型,如果您要在类扩展中覆盖声明的readonly部分,这很重要,因此您可以在实现中使用setter。类扩展属性覆盖只允许更改属性的readonly状态,因此必须在标头中正确声明其余部分(即原子性和所有权类型)。即使您现在没有覆盖该属性,也可能在将来使用,因此您可以使用正确的选项开始记录您希望如何管理内存。

自动引用计数(ARC)通过在经典引用计数规则之上叠加自己的内存管理规则来更改运行时实现细节,但配置属性的规则和建议保持不变。


为什么将retainreadonly一起使用?如果您将属性标记为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就有意义了。但是,在大多数其他情况下,您需要retaincopy

此外,实现文件只能覆盖属性声明的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(当它在完全未初始化的路上被半初始化时)。

为什么将-dealloccopy一起使用?在回答您的第一个问题时:因为readonlycopy对{{1}影响setter和getter。复制getter看起来像这样:

retain

为什么有时assign,有时/* getter for copy property */ - (NSString *)name { return [[name copy] autorelease]; } copy通常与值对象(表示值的被动对象)一起使用; retain通常与其他对象一起使用。有时候,效率问题会发挥作用(很可能过早地......),您可能会选择使用copy通常使用retain的地方。

你如何在这里使用retain / copy以及copy就像他们一样。我会覆盖类扩展中的声明,因此我可以使用setter来更改retainreadonly之外的属性值,其中我只使用直接实例变量访问。在-init中释放它们之后,我也会-dealloc出来,例如,

nil

这有助于避免向已发布的对象发送消息或以其他方式引用已发布的对象。