初始化和复制

时间:2012-07-06 18:17:11

标签: objective-c automatic-ref-counting

我刚刚阅读了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

2 个答案:

答案 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并且您具有设置该属性的便利初始值设定项,请确保便捷初始值设定项还复制对该属性设置的任何内容。