【问题标题】:Objective-c readonly copy properties and ivarsObjective-c 只读复制属性和 ivars
【发布时间】:2015-08-14 08:49:14
【问题描述】:

我正在尝试了解在 Objective-c 中声明为副本和只读的属性,特别是我是否必须自己进行副本。在我的初始化方法中。证据表明我这样做:

@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中创建一个只读属性来复制传入的值,或者它是否足以成为一种极端情况,这种组合是毫无意义的,无论如何我都必须手动复制自己?

【问题讨论】:

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


    【解决方案1】:

    @property 声明只是某些访问器/修改器方法声明的简写,并且(在某些情况下)是所述访问器/修改器方法的综合实现。

    在您的情况下,@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];
    }
    

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

    // 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
    

    【讨论】:

      【解决方案2】:

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

      可能有点难以理解,但实例变量与属性不是一回事。在这种情况下,它用于实现该属性。但是,赋值给实例变量和设置属性是不一样的。

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

          _test = [data copy];
      

      在初始化器中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-02
        • 1970-01-01
        • 1970-01-01
        • 2012-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-31
        相关资源
        最近更新 更多