7

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

我从 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)我能记住的是,在方法中/中copyretain可以的。initWithNamereleasedealloc

那么你会如何建议使用retain,copyreadonly在这个例子中呢?

4

1 回答 1

13

ETA: @DougW 正确指出属性的所有权类型 (assign/retain/copy) 不会影响 getter。它仍然会影响二传手。对于readonly类型,如果您要覆盖readonly类扩展中的声明部分,这很重要,因此您可以在实现中使用 setter。类扩展属性覆盖只允许更改readonly属性的状态,因此它的其余部分 - 这意味着原子性和所有权类型 - 必须在标题中适当地声明。即使您现在不覆盖该属性,但您将来可能会这样做,因此您不妨一开始就使用正确的选项来记录您希望如何为自己管理内存。

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


为什么使用retainwith readonly如果将属性标记为retain,则合成访问器会执行以下操作:

/* getter for retain property */
- (NSString *)name {
    return [[name retain] autorelease];
}

现在,如果您发送-name到的对象在您仍在使用它时更改了名称,则调用代码仍将具有对字符串的有效引用。但是,如果您将其声明为assign,它将是这样的:

/* getter for assign property */
- (NSString *)name {
    return name;
}

现在,一旦对象更改了名称,就必须将其释放以避免泄漏,这将使调用代码的引用无效。retain//实际上是在说明内存管理策略:/说copy,“我保证我持有对我在此处提供的值的原始/副本的引用,”同时说,“我只是拥有该值并声称不拥有参考这个。”assignretaincopyassign

当该值不需要内存管理时,例如 plain int,则assign有意义。当您有意不保留对象(例如委托)时,assign这是有道理的。但是,在大多数其他情况下,您会需要retainor copy

此外,实现文件只能覆盖属性声明的readwrite/readonly部分,而不是内存管理部分。如声明的那样,该.m文件可以具有:

@interface Holiday (/*class extension*/)
@property(nonatomic, retain, readwrite) NSDate *date;
/* override other properties to make them readwrite... */
@end

被覆盖的属性声明的非公共设置器将与公共访问器一起合成。

为什么不在 期间使用设置器/访问器-init因为 setter/accessors 经常执行 KVO 通知,当你的对象没有完全初始化时,你想避免这种情况,即在-init(当它在完全初始化的过程中被半初始化时)和-dealloc(当它在被初始化的过程中被半初始化时)完全未初始化)。

为什么使用copywith readonly就像回答你的第一个问题一样:因为 if copyvs retainvsassign会影响 setter 和 getter。复制 getter 如下所示:

/* getter for copy property */
- (NSString *)name {
    return [[name copy] autorelease];
}

为什么有时copy有时retain copy通常与值对象(表示值的被动对象)一起使用;retain通常与其他对象一起使用。有时,效率问题开始发挥作用(很可能过早......),您可能会选择retain在通常使用的地方使用copy.

你会如何在这里使用copy/ ?retainreadonly和他们做的差不多。我会覆盖类扩展中的声明,这样我就可以使用 setter 来更改-initand之外的属性值-dealloc,而我只会使用直接实例变量访问。我也会nil在发布 ivars 后将它们删除-dealloc,例如,

[name release], name = nil;

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

于 2010-10-28T15:41:14.880 回答