Objective-C访问器方法中的防御性拷贝

4

作为一个Java背景的开发者,在Objective-C中编写防御性程序有些困难。
假设SomeClass是可变的并且提供了一个copy方法,下面是我在Java中会编写的典型代码:

public MyClass  
{ 
    private SomeClass customerList;
    ...
    public SomeClass getCustomerList() {
        return this.customerList.copy(); 
    }
    public void setCustomerList(SomeClass list) {
        this.customerList = list.copy();
    }
}

我花了一些时间才弄清楚

@property (nonatomic, copy) SomeClass *customerList;  

在将参数分配给customerList属性之前,会复制setter的参数。让我困惑的是编写一个合适的getter。目前看起来是这样的:

(SomeClass *)customerList {  
    if(!_customerList) {  
        _customerList = [[SomeClass alloc] init];
    }
    return _customerList;
}  

这种方法适用于所有内部方法调用,例如self.customerList = ...,但对于创建安全漏洞的任何外部调用都会传递直接指针。我正在考虑提供一个不同的公共getter来返回副本,但希望避免这样做,因为它需要有一个非传统的名称。您会如何处理这种情况?
谢谢。

2个回答

3
你可以重写 -customerList 方法的实现为:return [_customerList copy];。但要注意这并不是其他人通常期望访问器工作的方式,所以请确保文档记录此事。

1
@JustSid 你说得对,我太匆忙了!实际上我不确定在ARC中这该怎么做。在手动保留/释放中,你需要添加一个autorelease。编辑:经过思考,我认为ARC会为你插入autorelease,但我不是完全确定... - Carl Veazey
据我所知,访问器不应直接提供对类内部实现的访问。返回一个副本可以提供外部世界可能需要的所有信息,但不会让它直接修改它。@Carl Veazey - Dmitry
通常情况下,这可以通过仅传递不可变对象来解决,除非允许调用者显式修改对象。 - JustSid
@Carl Veazey 这正是我正在尝试做的事情。只不过我不需要将其返回到内部方法的副本中。如果我表达不清楚,对不起。 - Dmitry
@Carl Veazey 没错!看来我得写单独的内部访问器了。谢谢你的帮助 :) - Dmitry
显示剩余5条评论

0
如果您想返回一个由属性及其getter支持的副本,使用以下形式非常容易:
@interface MyClass : NSObject
- (SomeClass *)copyCustomerList;
@end

@interface MyClass ()
@property (nonatomic, copy) SomeClass * customerList; // hide what you can
@end

@implementation MyClass
- (SomeClass *)copyCustomerList { return self.customerList.copy; }
@end

虽然你可以自己实现getter方法--但在ObjC中这是不常见的,正如Carl所提到的那样。

另一种方法是为实际属性使用不同的名称:

@interface MyClass : NSObject
- (SomeClass *)customerList;
@end

@interface MyClass ()
@property (nonatomic, copy) SomeClass * privCustomerList;
@end

@implementation MyClass

- (SomeClass *)customerList
{
 // -autorelease if MRC
 return self.privCustomerList.copy;
}

@end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接