Objective-c: двойные указатели на свойство недопустимы?
Я хочу создать такой метод:
- (void) checkAndUpdateStringProperty: (NSString **) property{
if (...)
*property = @"whatever";
}
Я хочу использовать это, чтобы передать свойство для того же класса:
- (void) somewhereElse{
....
[self checkAndUpdateStringProperty: &self.productName];
}
Но это дает синтаксическую ошибку, говоря "Запрос запроса свойства". Почему? Если я заменил свойство класса на локальную переменную, он отлично работает:
- (void) somewhereElse{
NSString *name = nil;
[self checkAndUpdateStringProperty: &name];
}
Ответы
Ответ 1
Свойства должны быть доступны только через их методы getter и setter, за исключением инициализации и деинициализации их в методах init
и dealloc
объекта (когда объект не находится в полностью согласованном состоянии) - доступ они каким-либо другим образом побеждают их цель и не уважают их атрибуты (retain
, copy
и т.д.).
Причина, по которой он не компилируется, заключается в том, что владельцы свойств являются синтаксическим сахаром для вызовов методов, и вы не можете взять адрес возвращаемого значения метода. self.productName
идентичен [self productName]
, а &[self productName]
не имеет смысла.
Если вы действительно хотите это сделать, не делайте этого с помощью свойства, делайте это с помощью только обычной переменной (например, локальной переменной или ivar) и документируйте семантику своей функции: нужна ли вызывающая функция to release
возвращенный объект? И т.д. Например, различные методы Apple, которые принимают NSError**
, указывают, что возвращаемый объект ошибки, если он есть, является автореализованным объектом, поэтому вы не должны release
его самостоятельно, если вы также не retain
его.
Ответ 2
В API Apple очень мало мест, в которых значение передается таким образом, главным из которых является NSError
. Лучше всего просто вернуть результат. Если у вас есть ссылочный параметр, общим правилом Apple является то, что он должен быть последним параметром, что имя метода начинается с "get
", как в getCheckAndUpdateStringProperty
.
Но вы можете это сделать, это просто не то, к чему мы привыкли.
Ошибка, которую вы видите, заключается в том, что self.productName
действительно сокращает вызов метода: [self productName]
, поэтому &self.productName
интерпретируется как &[self productName]
.
Далее в этом случае, если productName является @property с атрибутом сохранения, подсчет ссылок будет искажен.
Ответ 3
Если вы действительно внимательно относитесь к атрибутам собственности, вы можете обойти эту проблему, глядя на следующее:
[self property]
против
self.property
против
self->property
После того, как вы поняли разницу, вы можете попробовать следующее:
[self checkAndUpdateStringProperty: &self->productName]
Обратите внимание на использование: →
Я использую это все время, когда атрибут свойства присваивается и когда он является примитивным, не-объектным типом: (float, int,...)
Ответ 4
создать свойство этой переменной, к которой вы хотите получить доступ в другом классе (@property (сильный, неатомный);), а затем синтезировать его...
(@synthesize;), а затем доступ через имя объекта этого класса, где вы определяете свойство и синтезируете его.....
Ответ 5
Я бы сделал это с помощью селекторов (вам нужно будет преобразовать его в функцию ac, чтобы заставить его работать без предупреждения (см. здесь):
- (void) checkAndUpdateStringProperty: (SEL)setter {
if (...)
IMP imp = [self methodForSelector:setter];
void (*func)(id, SEL, id) = (void *)imp;
func(self, setter, @"whatever");
}
Используйте это для передачи в селектор для того же класса:
- (void) somewhereElse{
....
[self checkAndUpdateStringProperty:@selector(setProductName:)];
}