Нужно ли переопределять метод получения для свойства, чтобы вернуть неизменяемую копию?
Предположим, что у меня есть класс, который содержит изменяемый массив. Я хочу убедиться, что если другие классы будут запрашивать массив, они получат не изменяемый тип, но в классе-владельце это фактически экземпляр 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.