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

Objective-c: двойные указатели на свойство недопустимы?

Я хочу создать такой метод:

- (void) checkAndUpdateStringProperty: (NSString **) property{
   if (...) 
      *property = @"whatever";
}

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

- (void) somewhereElse{
       ....
       [self checkAndUpdateStringProperty: &self.productName];
}

Но это дает синтаксическую ошибку, говоря "Запрос запроса свойства". Почему? Если я заменил свойство класса на локальную переменную, он отлично работает:

- (void) somewhereElse{
       NSString *name = nil;
       [self checkAndUpdateStringProperty: &name];
}
4b9b3361

Ответ 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:)];
}