Подтвердить что ты не робот

NSArray @property, поддерживаемый NSMutableArray

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

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

@end

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

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

Спасибо!

4b9b3361

Ответ 1

Я бы объявил readonly NSArray в вашем заголовке и переопределил getter для этого массива, чтобы вернуть копию закрытого 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

Ответ 2

В основном, поместите свойство 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

Ответ 3

Простой:

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

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

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

Foo.m:

@implementation Foo {
    NSMutableArray* _array;
}

@end

foo.h:

@interface Foo

@property (readonly, strong) NSArray* array;

@end

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

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

Ответ 5

Это потому, что ваше свойство должно соответствовать фактическому типу класса 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 полностью, если это возможно.

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

@synthesize mutableArray = _mutableArray;

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

Ответ 6

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

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