Свойства только для чтения в Objective-C?
я объявил свойство readonly в моем интерфейсе как таковое:
@property (readonly, nonatomic, copy) NSString* eventDomain;
может быть, я неправильно свойства, но я думал, что когда вы объявляете его как readonly
, вы можете использовать сгенерированный сеттер внутри реализации (.m
файл), но внешние сущности не могут изменить значение. Это так вопрос говорит, что это то, что должно произойти. Именно такое поведение мне и нужно. Однако при попытке использовать стандартный синтаксис setter или dot для установки eventDomain
внутри моего init метод, это дает мне unrecognized selector sent to instance.
ошибка. Конечно, я @synthesize
ную собственность. Пытаясь использовать его так:
// inside one of my init methods
[self setEventDomain:@"someString"]; // unrecognized selector sent to instance error
так я не понимаю readonly
декларация на имущество? Или что-то еще происходит?
7 ответов:
вы должны сказать компилятору, что вы также хотите сеттер. Распространенный способ-поместить его в расширение класс в рамках .файл м:
@interface YourClass () @property (nonatomic, copy) NSString* eventDomain; @end
другой способ, который я нашел для работы со свойствами только для чтения, - использовать @synthesize для указания резервного хранилища. Например
@interface MyClass @property (readonly) int whatever; @end
тогда в реализации
@implementation MyClass @synthesize whatever = _whatever; @end
ваши методы могут затем установить _whatever, так как это переменная-член.
еще одна интересная вещь, которую я понял в последние несколько дней, - это вы можете сделать свойства только для чтения, которые доступны для записи подклассами:
(в заголовке файл)
@interface MyClass { @protected int _propertyBackingStore; } @property (readonly) int myProperty; @end
затем, в реализации
@synthesize myProperty = _propertyBackingStore;
он будет использовать объявление в заголовочном файле, поэтому подклассы могут обновлять значение свойства, сохраняя его только для чтения.
немного прискорбно с точки зрения сокрытия данных и инкапсуляции, хотя.
Эйко и другие дали правильные ответы.
вот более простой способ:прямой доступ к закрытой переменной-члену.
пример
в заголовке .H-файл:
@property (strong, nonatomic, readonly) NSString* foo;
в реализации .файл м:
// inside one of my init methods self->_foo = @"someString"; // Notice the underscore prefix of var name.
вот и все, это все, что вам нужно. Ни Мусса, ни суеты.
подробности
начиная с Xcode 4.4 и компилятора LLVM 4.0 (новые функции в Xcode 4.4), вам не нужно возиться с делами, обсуждаемыми в других ответах:
- The
synthesize
ключевое слово- объявление переменной
- повторное объявление свойства в реализации .m-файл.
после Объявления Недвижимость
foo
, можно предположить, что Xcode добавил закрытую переменную-член с префиксом подчеркивания:_foo
.если свойство было объявлено
readwrite
, Xcode генерирует метод getter с именемfoo
и сеттер по кличкеsetFoo
. Эти методы неявно вызываются при использовании точечной нотации (мой объект.myMethod). Если свойство было объявленоreadonly
, сеттер не генерируется. Это означает, что переменная backing, названная с подчеркиванием, является не только для чтения. Элементreadonly
означает просто, что метод setter не был синтезирован, и поэтому использование точечной нотации для установки значения завершается ошибкой компилятора. Точка нотация не выполняется, потому что компилятор останавливает вызов метода (сеттера), который не существует.самый простой способ обойти это-напрямую обратиться к переменной-члену, названной с подчеркиванием. Вы можете сделать это даже без объявления этой переменной с именем подчеркивания! Xcode вставляет это объявление как часть процесса сборки / компиляции, поэтому ваш скомпилированный код действительно будет иметь объявление переменной. Но вы никогда не увидите это объявление в исходном файле исходного кода. Не волшебство, просто синтаксический сахар.
используя
self->
- это способ доступа к переменной-члену объекта / экземпляра. Вы можете быть в состоянии пропустить, и просто использовать имя переменной. Но я предпочитаю использовать стрелку self+, потому что это делает мой код самодокументированным. Когда вы видитеself->_foo
вы знаете без двусмысленности, что_foo
является переменной-членом на этом экземпляре.
кстати, обсуждение плюсов и минусов доступа к собственности против прямого Ивара доступ к именно такой вдумчивый лечения, вы будете читать В Д Мэтт Нойберг ' s Программирование iOS книги. Мне было очень полезно читать и перечитывать.
посмотреть Настройка Существующих Классов в документах iOS.
только для чтения Указывает, что свойство доступно только для чтения. Если вы укажете только чтение, в реализации @требуется только метод getter. Если вы используете @synthesize в блоке реализации, синтезируется только метод getter. Кроме того, если вы попытаетесь присвоить значение с помощью синтаксиса dot, вы получите ошибку компилятора.
свойства только для чтения имеют метод getter. Вы все еще можете установить резервный ivar непосредственно в классе свойства или с помощью кодирования значения ключа.
вы неправильно поняли другой вопрос. в этом вопросе есть расширение класса, объявленное таким образом:
@interface MYShapeEditorDocument () @property (readwrite, copy) NSArray *shapesInOrderBackToFront; @end
это то, что генерирует сеттер, видимый только в реализации класса. Так как Eiko говорит, вам нужно объявить расширение класса и переопределить объявление свойства, чтобы сообщить компилятору о создании сеттера только внутри класса.
короткий ответ:
MyClass.h
@interface MyClass { int myProperty; } @property (readonly) int myProperty; @end
MyClass.h
@implementation MyClass @synthesize myProperty; @end
если свойство определено как readonly, это означает, что фактически не будет сеттера, который можно использовать либо внутри класса, либо снаружи из других классов. (т. е.: у вас будет только "геттер", если это имеет смысл.)
из его звуков Вы хотите, чтобы обычное свойство чтения / записи было помечено как private, что вы можете достичь, установив переменную класса как private в вашем интерфейсном файле:
@private NSString* eventDomain; }