Напишите только свойство в Objective-C

Я застрял со свойствами Objective-C. Что мне нужно, так это присвоить переменной свойство только для записи, прямо противоположное свойству только для чтения, т.е. переменная может иметь setMethod, но не должна иметь getMethod. Я не знаю, как это сделать. ответы с некоторыми фрагментами кода приветствуются.


person KingofHeaven    schedule 24.11.2010    source источник
comment
Какая польза от свойства только для записи? ИМХО это только пустая трата памяти.   -  person Eimantas    schedule 24.11.2010
comment
Много применений; обычно, когда вы хотите, чтобы что-то было общедоступным только для записи и внутренне для класса, оно предназначено для чтения и записи.   -  person bbum    schedule 24.11.2010
comment
Когда внешний класс знает переменную, которую нужно передать, но у него нет причин знать, какое значение она имеет в данный момент.   -  person ArtOfWarfare    schedule 20.10.2013


Ответы (3)


Вы можете сделать что-то вроде:

@interface MyClass {
@private
int _var;
}

- (void)setVar:(int)newVar;
@end

@implementation MyClass
- (void)setVar:(int)newVar {
_var = newVar;
}
@end

Теперь вы можете получить доступ к переменной var как к свойству, доступному только для записи:

@implementation SomeOtherClass
...
MyClass c = [[MyClass alloc] init];
c.var = 3;
...
@end

И если вы попытаетесь прочитать поддельное свойство, компилятор предупредит вас.

person Bruno Berisso    schedule 24.11.2010
comment
Необходимо определить метод -(void)setVar:(int)newVar в реализации, а также в интерфейсе. - person JeremyP; 24.11.2010
comment
Имейте в виду, что это не полностью скрывает значение. Если вы не переопределите (BOOL)accessInstanceVariablesDirectly с помощью NO, вы можете получить значение с помощью valueForKey:@var. И даже если вы переопределите это, вы все равно можете получить значение с помощью метода времени выполнения objC, такого как object_getInstanceVariable. - person w-m; 24.11.2010
comment
@kubbing Технически это собственность. Свойство в Obj-C — это просто причудливое название для двух методов: getter и setter. Вы можете объявить геттер без использования @property, и поведение будет точно таким же, как и с @property. То же самое относится и к сеттеру. Вы даже можете использовать запись через точку. - person Sulthan; 18.02.2013
comment
@Sulthan Это почти правильно, отчасти из-за того, что среда выполнения делает это различие. Свойство fake, подобное этому, например, не будет отображаться при использовании class_copyPropertyList. Смотрите мой ответ для другого подхода. - person Gabriele Petronella; 05.09.2013
comment
@GabrielePetronella Это правда, но в 99% случаев разница не имеет значения. Даю вам +1 в любом случае, потому что это хорошее решение :) - person Sulthan; 05.09.2013
comment
@Султан Согласен. Вероятно, самым большим преимуществом моего решения является автозаполнение (и оно тоже короче ;)). - person Gabriele Petronella; 05.09.2013
comment
Наличие реального свойства имеет значение, если вы используете класс со Swift. Если это не свойство, вы не можете использовать точечную запись в Swift. - person ThomasW; 07.07.2014

Другой допустимый подход — объявить свойство normal и сделать геттер недоступным.

@interface MyClass
@property NSString * var;
- (NSString *)var UNAVAILABLE_ATTRIBUTE;
@end

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


Основное преимущество этого подхода заключается в том, что вы фактически имеете реальное свойствоTM, а не суррогат, подделанный переменной экземпляра и сеттером, что подразумевает, что:

  • вы получите автозаполнение при использовании точечной записи в Xcode
  • все функции среды выполнения, такие как class_getProperty и class_copyPropertyList, будут работать должным образом.

Тем не менее, реализация геттера в любом случае синтезируется, и ее можно вызвать с помощью чего-то вроде

NSString * string = [myObj performSelector:@selector(var)];

или используя NSInvocation (в случае свойства, отличного от id)

Если вы параноик и на самом деле хотите, чтобы клиент не вызывал геттер, вы можете явно создать исключение, предоставив собственную реализацию.

@implementation MyClass
- (int)var {
    [NSException raise:NSInternalInconsistencyException
                format:@"property is write-only"];
}
@end

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

person Gabriele Petronella    schedule 05.09.2013
comment
это доступно для LLVM? - person Mingming; 01.09.2014

Есть ли причина, по которой это должно быть собственностью? Я бы просто объявил сеттер как метод и использовал обычный синтаксис [foo setVar:bar].

person grahamparks    schedule 24.11.2010
comment
Да, это работает, но xCode, похоже, не выполняет автоматическое заполнение var при вводе. - person Fredrik Johansson; 20.09.2012
comment
@FredrikJohansson, ты прав. Для удобного решения с автоматическим завершением вы можете проверить мое решение. - person Gabriele Petronella; 05.09.2013