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

tes*_*ing 7 iphone initialization properties objective-c 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
Run Code Online (Sandbox Code Playgroud)

1)属性设置为retain,但由于不能使用setter,因此retain这里没有意义.

2)此外,在initWithName方法中设置值copy.为什么不直接copy使用访问器方法定义属性?

@property (nonatomic, copy) NSString *name;
// ...
self.name = aName;
Run Code Online (Sandbox Code Playgroud)

3)我需要readonly这里吗?我不知道他们为什么在这里使用.如果我将copy与setter一起使用,则readonly禁止我设置值,因为没有setter.

4)在该initWithName方法中,有时copy并且有时retain使用.我建议总是copy在这里使用,因为以后不应修改该值.

5)我能记住的是,它是确定copy/ retaininitWithNamereleasedealloc方法.

所以,你会如何建议使用retain,copy并且readonly在这里这个例子吗?

Jer*_*man 13

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

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


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

/* getter for retain property */
- (NSString *)name {
    return [[name retain] autorelease];
}
Run Code Online (Sandbox Code Playgroud)

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

/* getter for assign property */
- (NSString *)name {
    return name;
}
Run Code Online (Sandbox Code Playgroud)

现在,只要对象更改了名称,就必须释放它以避免泄漏,这将使调用代码的引用无效.该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
Run Code Online (Sandbox Code Playgroud)

覆盖的属性声明的非公共setter将与公共访问器一起合成.

为什么不在期间使用setter/accessors -init因为setter/accessors经常执行KVO通知,当你的对象没有完全初始化时,你想要避免-init它,(在它完全初始化的过程中它被半初始化时)和-dealloc(当它被初始化为一半时)完全未初始化).

为什么要使用copyreadonly正如对你的第一个问题的回答:因为如果copyretain对比同时assign影响了二传手和吸气者.复制getter看起来像这样:

/* getter for copy property */
- (NSString *)name {
    return [[name copy] autorelease];
}
Run Code Online (Sandbox Code Playgroud)

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

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

[name release], name = nil;
Run Code Online (Sandbox Code Playgroud)

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