Нужно ли переопределять метод получения для свойства, чтобы вернуть неизменяемую копию?

Предположим, что у меня есть класс, который содержит изменяемый массив. Я хочу убедиться, что если другие классы будут запрашивать массив, они получат не изменяемый тип, но в классе-владельце это фактически экземпляр NSMutableArray, так что я могу добавлять и удалять элементы.

#import "Person.h"

@class Asset;

@interface Employee : Person

{
    NSMutableArray *_assets;
}

@property (nonatomic,copy) NSArray *assets;

-(void)addAssets:(Asset *)a;

Вопрос в том, нужно ли мне модифицировать методы доступа как-то так, или они будут автоматически вести себя так, как я хочу?

#import "Employee.h"
#import "Asset.h"

@implementation Employee

/* Accessors for assets properties
-(NSArray *)assets
{
    return [_assets copy];
}

-(void)setAssets:(NSArray *)assets
{
    _assets = [assets mutableCopy ];

}
*/

-(void)addAssets:(Asset *)a
{
    //is assets nil?

    if (!_assets) {
        //Create Array
        _assets = [[NSMutableArray alloc]init];
    }
    [_assets addObject:a];

}

2 ответа

Решение

ppalancica ответ неверный. copy Атрибут означает только то, что установщик получит копию, когда свойство установлено. Синтезированный геттер не вернет копию. Вы должны реализовать это поведение самостоятельно:

- (NSArray *)assets
{
    return [_assets copy];
}

Возможно, вы захотите сделать внутренний метод доступа, который не делает копию. Вы также можете переопределить собственность в частном порядке; Затем будет заключен контракт с клиентским кодом для обработки запрашиваемого массива как неизменяемого.

Этот код демонстрирует, что синтезированный геттер возвращает не скопированный объект:

#import <Foundation/Foundation.h>

@interface ArrayReturner : NSObject

@property (copy, nonatomic) NSArray * array;

@end

@implementation ArrayReturner
{
    NSMutableArray * _array;
}

- (BOOL)myArrayIsIdenticalTo:(NSArray *)otherArray
{
    return _array == otherArray;
}

@end

int main(int argc, const char *argv[])
{
    @autoreleasepool {

        ArrayReturner * a = [ArrayReturner new];
        [a setArray:@[@1, @2]];
        NSArray * returnedArray = [a array];
        // Does not throw
        NSCAssert([a myArrayIsIdenticalTo:returnedArray],
                  @"Returned array is a separate instance.");
    }

    return 0;
}

Поскольку вы уже указали атрибут "copy" для свойства массива, нет необходимости переопределять метод получения и установки. Компилятор сделает всю тяжелую работу за вас.

Если вместо этого вы укажете "strong", метод получения и установки будет выглядеть следующим образом:

-(NSArray *)assets
{
    return _assets;
}

-(void)setAssets:(NSArray *)assets
{
    _assets = assets;
}

И это может быть проблемой.

На самом деле есть конференция WWDC, которая объясняет все эти детали. Для свойств NSString более рекомендуется использовать copy, и вы можете увидеть это очень похоже на каркас iOS SDK.

Другие вопросы по тегам