NSArray @property при поддержке NSMutableArray - PullRequest
39 голосов
/ 07 декабря 2011

Я определил класс, в котором я хотел бы, чтобы открытое свойство выглядело так, как будто оно поддерживается NSArray. Это достаточно просто, но в моем случае фактический резервный ivar - это NSMutableArray:

@interface Foo
{
    NSMutableArray* array;
}
@property (nonatomic, retain) NSArray* array;

@end

В моем файле реализации (*.m) я @synthesize свойство, но я сразу же сталкиваюсь с предупреждениями, потому что использование self.words - это то же самое, что пытаться изменить NSArray.

Как правильно это сделать?

Спасибо!

Ответы [ 6 ]

21 голосов
/ 07 декабря 2011

Я бы объявил readonly NSArray в вашем заголовке и переопределил метод получения для этого массива, чтобы он возвращал копию частного NSMutableArray, объявленного в вашей реализации. Подумайте о следующем.

foo.h

@interface Foo

@property (nonatomic, retain, readonly) NSArray *array;

@end

Foo.m

@interface Foo ()

@property (nonatomic, retain) NSMutableArray *mutableArray

@end

#pragma mark -

@implementation Foo

@synthesize mutableArray;

- (NSArray *)array
{
    return [[self.mutableArray copy] autorelease];
}

@end
14 голосов
/ 10 мая 2012

По сути, поместите свойство NSArray в категорию в вашем заголовочном файле и свойство NSMutableArray в расширении класса в вашем файле реализации.Вот так ...

Foo.h:

@interface Foo
@end

@interface Foo (Collections)
@property (nonatomic, readonly, strong) NSArray *someArray;
@end

Foo.m

@interface Foo ()
@property (nonatomic, readwrite, strong) NSMutableArray *someArray;
@end
5 голосов
/ 07 декабря 2011

Simple:

1) Не используйте свойство, когда оно не одно.

2) Код упрощается до:

- (NSArray *)currentArray {
    return [NSArray arraywithArray:mutableArray]; // need the arrayWithArray -    otherwise the caller could be in for surprise when the supposedly unchanging array changes while he is using it. 
}

- (void)setArray:(NSArray *)array {
    [mutableArray setArray:array];
}

Когда объект выделен, создайте массив, когда он умрет, освободите массив.

Когда большие эффекты возникают при простом использовании «.» оператор, его легко пропустить чрезвычайно неэффективный код. Аксессоры - это просто. Также - если кто-то вызывает aFoo.array - контракт заключается в том, чтобы получить доступ к членам массива foo, но на самом деле это просто копия во время вызова. Разница настолько реальна, что она вызвала ошибки в других добавлениях, опубликованных здесь.

4 голосов
/ 07 августа 2013

Обновление: этот ответ больше не действителен. Используйте одно из предложенных решений ниже.

В эти дни вы можете делать следующее:

Foo.m:

@implementation Foo {
    NSMutableArray* _array;
}

@end

foo.h:

@interface Foo

@property (readonly, strong) NSArray* array;

@end

Вы по-прежнему можете обращаться к изменяемым _array с помощью ivar изнутри реализации, и снаружи он будет доступен через неизменяемое свойство. К сожалению, это не гарантирует, что другие не смогут привести его к NSMutableArray и изменить. Для лучшей защиты от идиотов вы должны определить метод доступа и вернуть неизменяемую копию, однако в некоторых случаях это может быть очень дорого.

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

2 голосов
/ 07 декабря 2011

Это потому, что ваша собственность должна соответствовать фактическому типу класса ivar.

Возможное решение / обходной путь:

//Foo.h:
@interface Foo
{
    NSMutableArray* mutableArray;
}
@property (readwrite, nonatomic, retain) NSArray* array;
//or manual accessor declarations, in case you're picky about wrapper-properties.
@end

//Foo.m:
@interface Foo ()
@property (readwrite, nonatomic, retain) NSMutableArray* mutableArray;
@end

@implementation

@synthesize mutableArray;
@dynamic array;

- (NSArray *)array {
    return [NSArray arrayWithArray:self.mutableArray];
}

- (void)setArray:(NSArray *)array {
    self.mutableArray = [NSMutableArray arrayWithArray:array];
}

@end

Вы добавляете частное свойство mutableArray в расширение класса и делаете общедоступным array просто перенаправление на ваше личное изменяемое свойство.

С последними расширениями языка ObjC я склонен удалить

{
    NSMutableArray* mutableArray;
}

Блок Ивара полностью, если это возможно.

И определить ivar через синтез, как таковой:

@synthesize mutableArray = _mutableArray;

, который сгенерирует для вас экземпляр NSMutableArray *_mutableArray;.

0 голосов
/ 11 декабря 2014

Простейший ответ: тип вашего свойства (NSArray) не соответствует типу переменной вашего экземпляра (NSMutableArray).

Это еще одна веская причина, по которой вам не следуетопределите свои собственные переменные поддержки. Позвольте @synthesize настроить переменные вашего экземпляра;не делай этого вручную.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...