Pregunta

I've just encountered a little surprise whilst writing NSCoder support into a class. I have a class A which contains an exposed 'color' property of an rgb struct type. I have another class B which extends A.

To encode the color property within class B's encodeWithCoder method I've first wrapped it into an NSValue like so:

[NSValue value:&(self.color)]

However using this code causes the following compilation error:

Lvalue required as unary '&' operand.

It's easy enough to get around by simply copying self.color to a method-scope value before wrapping with NSValue, but I'd like to understand the rule for when this will happen, and why it occurs. Will this happen with any @synthesize property due to there being no need for a true class field of that property name to exist, hence no guaranteed object to point to?

¿Fue útil?

Solución

The rule is simple enough. The compiler turns a property access:

self.color

into a method call*

[self color]

which means that &(self.color) turns into &([self color]). Then the compiler complains, because you can't take the address of a method call.


*If you were assigning to the property, the assignment would be transformed into a call to the setter: self.color = aColor; -> [self setColor:aColor];.

Otros consejos

You cannot get the address of something returned by a function (or method). You need to get the address of the color ivar directly (i.e. &color). In your case though, I recommend using the approach you proposed yourself (id tempCol = self.color; [NSValue value:&tempCol];).


Note that a method is invoked when using dot notation.

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

&([self color]) is also impossible because & is resolved at compile-time, not at runtime. The return value of [self color] and self.color (which are equal) aren't yet known at compile-time (even when using @synthesize, since you can change a method's implementation in Objective-C at runtime (e.g. with method swizzling or using categories)).


It seems that you don't fully understand what @synthesize does, so I'll explain. :)

Basically what @synthesize does is this: the compiler generates methods and their implementations from the given property names.

For example, this property:

@property(nonatomic, retain) NSColor *color;

Together with this synthesization:

@synthesize color;

Will insert this code for you in the @implementation:

- (NSColor *)color {
  return color;
}

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

When you like to use your own setter or getter, you simply define these in the @implementation by using the same method names. You could, for example, return a default color if none is set yet:

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

Now the compiler will generate the setter, but not the getter: it will use the getter you provided, you can still use it with self.color.


You may want to take a look at Apple's guide on properties.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top