Указатель свойства структуры Objective-C не может быть сделан через self.prop? - PullRequest
3 голосов
/ 18 августа 2011

Я только что столкнулся с небольшим удивлением, когда записывал поддержку NSCoder в класс.У меня есть класс A, который содержит открытое свойство 'color' типа struct rgb.У меня есть другой класс B, который расширяет A.

Для кодирования свойства цвета в методе encodeWithCoder класса B я сначала обернул его в NSValue, например:

[NSValue value:&(self.color)]

Однако, используя этот кодвызывает следующую ошибку компиляции:

Lvalue required as unary '&' operand.

Достаточно легко обойти, просто скопировав self.color в значение области метода перед переносом с NSValue, но я хотел бы понять правило, когда этобудет, и почему это происходит.Произойдет ли это с любым свойством @synthesize из-за того, что нет необходимости в существовании поля истинного класса для этого имени свойства, следовательно, нет гарантированного объекта, на который можно указать?

Ответы [ 2 ]

4 голосов
/ 18 августа 2011

Вы не можете получить адрес чего-либо, возвращенного функцией (или методом). Вам необходимо получить адрес ивара color напрямую (т.е. &color). Однако в вашем случае я рекомендую использовать предложенный вами подход (id tempCol = self.color; [NSValue value:&tempCol];).


Обратите внимание, что метод вызывается при использовании точечной нотации.

self.color
// is equal to
[self color]

&([self color]) также невозможно, поскольку & разрешается во время компиляции, а не во время выполнения. Возвращаемые значения [self color] и self.color (которые равны) еще не известны во время компиляции (даже при использовании @synthesize, поскольку вы можете изменить реализацию метода в Objective-C во время выполнения (например, с помощью метода извращение или использование категорий)).


Кажется, вы не до конца понимаете, что делает @synthesize, поэтому я объясню. :)

По сути, @synthesize делает следующее: компилятор генерирует методы и их реализации из заданных имен свойств.

Например, это свойство:

@property(nonatomic, retain) NSColor *color;

Вместе с этим синтезом:

@synthesize color;

Вставит этот код для вас в @implementation:

- (NSColor *)color {
  return color;
}

- (void)setColor:(NSColor *)newColor {
  if (color == newColor) { return; }
  NSColor *theOldColor = color;
  color = [newColor retain];
  [theOldColor release];
}

Когда вы хотите использовать свой собственный установщик или получатель, вы просто определяете их в @implementation, используя те же имена методов. Например, вы можете вернуть цвет по умолчанию, если он еще не установлен:

- (NSColor *)color {
  if (color) { return color; }
  return [NSColor whiteColor];
}

Теперь компилятор будет генерировать установщик, но не получатель: он будет использовать предоставленный вами получатель, вы все равно можете использовать его с self.color.


Возможно, вы захотите взглянуть на Руководство Apple по свойствам .

3 голосов
/ 18 августа 2011

Правило достаточно простое. Компилятор превращает свойство в доступ:

self.color

в вызов метода *

[self color]

, что означает, что &(self.color) превращается в &([self color]). Затем компилятор жалуется, потому что вы не можете взять адрес вызова метода.


* Если вы присваиваете свойству свойство, присваивание будет преобразовано в вызов установщика: self.color = aColor; -> [self setColor:aColor];.

...