我刚刚阅读了Craig Hockenberry关于ARC and copy的简短博文。我现在的问题是,传递给分配给实例变量的初始值设定项的参数是否应始终使用copy
?或者它取决于实例变量的类型?
#import "MyObject.h"
@implementation MyObject {
SomeType *_ivar1;
SomeOtherType *_ivar2;
}
-(id)initWithParam1:(SomeType *)param1 andParam2:(SomeOtherType *)param2
{
if ((self == [super init])) {
_ivar1 = [param1 copy]; // Always good
_ivar2 = [param2 copy]; // practice?
}
return self;
}
@end
答案 0 :(得分:4)
我认为理解这篇文章的关键在于这句话:
由于我认为在-init期间使用访问器是一个坏主意,因此永远不会使用由
@property
定义的复制语义,并且ARC很乐意保留引用而不是复制它。
我认为克雷格特别谈到以下案例:
@interface MyObject : NSObject {
SomeType *_ivar1;
}
-(id)initWithParam1:(SomeType *)param1;
@property (copy, nonatomic) SomeType* prop1;
@end
@implementation MyObject
@synthesize prop1 = _ivar1;
-(id)initWithParam1:(SomeType *)param1 {
if ((self == [super init])) {
/*
Craig could have called
self.prop1 = param1;
but he believes that it's a bad idea to call accessors
from the initializer, so he calls copy explicitly.
*/
_ivar1 = [param1 copy];
}
return self;
}
@end
答案 1 :(得分:2)
取决于变量和意图的类型。
对于简单类型 - NSString,NSArray,NSNumber等... - 您使用副本,因为您通常希望存储的类型是不可变的。即拥有firstName
属性是没有意义的,外部的东西可以通过传递NSMutableString
的实例来修改它。
对于更复杂的类 - 包含状态和功能的类 - 您通常不希望完全复制它,因为该状态可能随时间而变化。例如,如果您的应用是一个流媒体视频应用,其中有一个播放封装在StreamingVideo实例中的视频的VideoPlayer实例,您不希望复制StreamingVideo,因为随着更多数据的下载,其内部状态将不断变化(或发生错误)。
即。当您需要状态的不可变快照时使用copy
,并且当您希望将对象A连接到B以便更改/监视/查询B的状态时使用引用。
而且,是的,你希望它保持一致。如果属性为copy
并且您具有设置该属性的便利初始值设定项,请确保便捷初始值设定项还复制对该属性设置的任何内容。