Objective - C内存管理编程指南(5)存取方法

存取方法

本章向您介绍为什么应该使用存取方法,以及您应该如何声明和实现它们。

使用存取方法的一个主要原因是封装(见Objective-C面向对象编程中的封装部分)。在引用计数环境中,使用存取方法还有一个特别的好处,它们可以为您的类处理大部分的基本内存管理。

声明存取方法

通常,您应该使用Objective - C属性声明功能来声明存取方法,例如:

@property (copy) NSString *firstName;
@property (readonly) NSString *fullName;
@property (retain) NSDate *birthday;
@property NSInteger luckyNumber;

上述声明为属性指定了明确的内存管理语义。

实现存取方法

在很多情况下,您可以(而且应该)避免实现您自己的存取方法,而使用Objective-C属性声明功能,并要求编译器为您合成存取方法:

@synthesize firstName;
@synthesize fullName;
@synthesize birthday;
@synthesize luckyNumber;

即使您需要提供您自己的实现,您也应该使用声明属性来声明存取方法当然,您必须保证您的实现符合您给出的规范。(要特别注意的是,在默认情况下,声明属性是原子的;如果您不提供原子的实现,那么您应该在声明中指定nonatomic。)

对于简单的对象值来说,大致有三种方式来实现存取方法:

1. Getter在返回值之前保留并自动释放该值;setter释放旧的值并保留(或复制)新的值。

2. Getter返回值;setter自动释放旧的值并保留(或复制)新的值。

3. Getter返回值;setter释放旧的值并保留(或复制)新的值。

方法 1

在方法1中,getter返回的值在调用作用域内被自动释放:

- (NSString*) title {
 return [[title retain] autorelease];
}
- (void) setTitle: (NSString*) newTitle {
 if (title != newTitle) {
 [title release];
 title = [newTitle retain]; // Or copy, depending on your needs.
 }
}

由于get存取器返回的对象在当前作用域内被自动释放,因此,如果属性的值发生改变,它仍然有效。这使得存取器更加健壮,但额外开销更多。如果您希望您的getter方法能够被频繁调用,则您也应该考虑到,相比于这种做法带来的性能开销,保留和自动释放对象所增加的额外开销是很不值得的。

方法 2

和方法1一样,方法2也使用了自动释放技术,但这次是在setter方法中完成:

- (NSString*) title {
 return title;
}
- (void) setTitle: (NSString*) newTitle {
 [title autorelease];
 title = [newTitle retain]; // Or copy, depending on your needs.
}

gettersetter调用更频繁的情况下,方法2的性能明显好于方法1

方法 3

方法3完全没有使用自动释放技术:

- (NSString*) title {
 return title;
}
- (void) setTitle: (NSString*) newTitle {
 if (newTitle != title) {
 [title release];
 title = [newTitle retain]; // Or copy, depending on your needs.
 }
}

方法3所采用的方式非常适合于gettersetter方法被频繁调用的情况。它也非常适合于那些不希望延长值的生命周期的对象,比如集合类。它的缺点是,旧的值可能被立即回收(如果没有其他的所有者),如果另一个对象持有指向该值的非所有性引用,那么这将导致一个问题。例如:

NSString *oldTitle = [anObject title];
[anObject setTitle:@"New Title"];
NSLog(@"Old title was: %@", oldTitle);

如果anObject是拥有原始标题字符串的唯一对象,那么该字符串会在新的标题被设置之后被回收。随后,日志语句将引起程序崩溃,因为oldTitle是一个已被释放的对象。

值对象和复制

Objective-C代码中,复制值对象表示属性的对象是一种很普遍的做法。C-类型的变量通常可以取代值对象,但值对象具有封装常用操作的优势。例如,NSString对象被用来代替字符指针,因为它们封装了编码和存储。

当值对象作为方法的参数被传递或者从一个方法被返回时,通常会使用对象的副本而不是对象本身。例如,请仔细思考下面的方法,该方法将一个字符串赋值给对象的name实例变量。

- (void)setName:(NSString *)aName {
 [name autorelease];
 name = [aName copy];
}

存储aName的一个副本,其效果是产生一个独立于原始对象,但与原始对象具有相同内容的对象。副本的后续变化不会影响原始对象,并且原始对象的变化也不会影响副本。类似地,一种常见的做法是返回实例变量的副本,而不是实例变量本身。例如,下面的方法返回name实例变量的一个副本:

- (NSString *)name {
 return [[name copy] autorelease];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值