Objective-c只读复制属性和ivars

时间:2015-06-01 00:50:59

标签: objective-c properties automatic-ref-counting

我尝试在objective-c中尝试声明为copy和readonly的属性,具体来说,我是否必须自己复制。在我的init方法中。证据表明我做了:

@interface A : NSObject 
    @property(nonatomic, copy, readonly) NSData *test;
    - (instancetype)initWithData:(NSData *)data;
@end

@implementation A

- (instancetype)initWithData:(NSData *)data {
    if ((self = [super init]) != nil) {
        _test = data;
    }
    return self;
}

@end


int main (void) {
    NSData *d1 = [NSMutableData dataWithBytes:"1234" length:5];
    A *a = [[A alloc] initWithData:d1];

    NSLog(@"%lx", (unsigned long)d1);
    NSLog(@"%lx", (unsigned long)a.test);
    return 0;
}

我以为我可以在我的init方法中执行self.test = data,但这是不允许的,因为它只读(非意外)。当然,self.test = [data copy]可以确保两个不同的对象。

所以:有没有办法在objective-c中创建一个复制传入值的readonly属性,或者它是否足以构成组合毫无意义的边缘情况,我必须手动复制自己?

2 个答案:

答案 0 :(得分:1)

@property声明只是一些accessor / mutator方法声明的简写,并且(在某些情况下)是所述accessor / mutator方法的合成实现。

在您的情况下,@property(nonatomic, copy, readonly) NSData *test声明扩展为此等效代码:

@interface A : NSObject
{
    NSData* _test;
}
- (NSData*)test;
@end

@implementation A
- (NSData*)test
{
    return _test;
}
@end

没有setTest: mutator方法,因为该属性声明为readonly,因此copy属性无效。

您可以实现自己的mutator方法:

- (void)setTest:(NSData*)newValue
{
    _test = [newValue copy];
}

或者,您可以让编译器通过在实现文件中声明私有类扩展中的读/写属性来为您合成mutator方法:

// A.m:

@interface A() 
@property (nonatomic, copy) NSData* test;
@end

这两种情况都允许您使用test mutator方法将值复制到_test实例变量:

- (instancetype)initWithData:(NSData *)data {
    if ((self = [super init]) != nil) {
        self.test = data;
    }
    return self;
}

最终结果是:

@interface A : NSObject
@property(nonatomic, copy, readonly) NSData* test;
- (instancetype)initWithData:(NSData*)data;
@end

@interface A()
@property (nonatomic, copy) NSData* test;
@end

@implementation A
- (instancetype)initWithData:(NSData*)data {
    if ((self = [super init]) != nil) {
        self.test = data;
    }
    return self;
}
@end

答案 1 :(得分:0)

除了Darren所说的,copy属性描述了属性设置器具有的语义。在初始值设定项中,您没有使用setter,而是直接分配给实例变量。

可能有点难以理解,但实例变量与属性不同。在这种情况下,使用来实现属性。但是,分配实例变量与设置属性不同。

如果您希望初始化程序也具有复制传入数据的语义,那么这是一个单独的设计决策(尽管最好使用属性的语义)。您可以通过使用Darren建议的私有设置器来实现它,但您也可以这样做:

    _test = [data copy];
初始化程序中的