在ObjectiveC中,对于只读属性,是否需要声明strong或copy?

3
在Objective-C中,通常将NSString / NSArray / NSDictionary声明为复制(copy),但对于只读属性是否有必要这样做或者没有区别呢? 如果一个NSString是只读的,那么它永远不会被设置,因此声明为strong还是copy会产生相同的效果,对吗?

//在这里使用strong而不是copy,因为它永远不会被复制,所以两者的效果相同?

@property (nonatomic, readonly) NSString *string;


https://dev59.com/1Ggv5IYBdhLWcg3wTvHL - hariszaman
3个回答

5

如果它真的是只读的,那么你不需要指定它。如果你要重新声明它为私有的readwrite,那么你需要指定它。对于readonly属性,它没有任何影响,因为不会创建setter。


0
你是对的,但有些事情需要考虑。只要你的属性是不可变对象,那么这样做就没问题。然而,并非总是如此。
第一个例子,我经常遇到的情况是,当你的实现内部有可变对象时。比如在实现中声明了NSArray属性,它实际上可以是NSMutableArray。强引用属性getter会返回指向该NSMutableArray的指针。在某个时刻,你可能会请求从对象中获取NSArray,对其进行一些操作,然后 - 嘭!你的NSArray具有不同的元素数量?怎么回事?在这种情况下,更好的主意是在getter中复制你使用的内部实现中的NSMutableArray。
另一个例子是某个模型对象。
@interface Person : NSObject <NSCopying>
@property NSString *name;
@property NSDate   *birthdate;
@end

而且您还有一些具有属性的其他接口

@property (strong, readonly) Person *person;

是的,你不能将不同的对象分配给此属性。但是,你可以修改它的字段,使其表示完全不同的人。如果你不想要这样的行为 - 将其设置为copy属性。或者将其设置为私有,并使用访问方法来获取其字段。

- (id) getHiddenPersonPropertyValueForKey:(NSString *)personPropertyKey;

或者任何其他方式


如果它是可变的,那会有什么影响呢?复制行为只需要由实现setter方法的人定义就可以了,不是吗? - Boon
如果您自己实现setter方法 - 它返回什么其实是由您决定的(只要它与返回值类型相对应)。但是您也可以简单地使用@synthesize。因此,为了让编译器知道您需要复制此属性的实际实现 - Sergii Martynenko Jr
我的意思是复制属性不应该影响您使用可变或不可变数组,因为它是只读的。这不是这种情况吗? - Boon
Readonly 的意思是你不能设置全新的对象(将指针设置为内存中的另一个对象)。这并不意味着对象本身是不可变的 - 就像第二个例子一样。 - Sergii Martynenko Jr
我理解你的意思,实际上我认为一个复制属性应该在getter中也进行复制。然而,按照惯例,如果一个对象承诺返回一个不可变对象,但在调用者背后改变了对象,则违反了合同。 - JeremyP
由于封装原则的存在,实际实现的内容并不重要。如果您拥有属性NSArray,这并不意味着在内存中实际存储了任何NSArray - 它可能是您存储在文件系统中的某些内容。 - Sergii Martynenko Jr

0
如果属性代表真正不可变的值(例如NSArrayNSIndexSet等),那么只需要使用readonly即可,因为它将按原样返回不可变的值。
但是,在私有实例变量是可变的情况下(例如NSMutableArray实例变量与属性的NSArray类型),您应该返回一个副本,以防止未来内部更改泄漏到调用者的状态中。
@interface MyObject : NSObject {
    NSMutableArray *_array;
}

@property(nonatomic, readonly) NSArray *array;
// -or-
- (NSArray *)array;

@end

并且

@implementation

@dynamic array; // only if @property was declared in interface

- (NSArray *)array
{
    return [_array copy];
}

@end

调用者可以安全地存储属性的值,并期望即使没有进行显式复制,它也不会改变:
self.array = [myObject array]; // e.g. 1 element
[myObject addElementToArray:@(42)];
NSLog(@"%@", self.array); // still 1 element

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