Pregunta

I do not have anything in particular to achieve, but rather I am trying to learn more about class extension.

This is the explanation of class extension directly from apple Categories and extensions:

@interface MyClass : NSObject
@property (retain, readonly) float value;
@end

// Private extension, typically hidden in the main implementation file.
@interface MyClass ()
@property (retain, readwrite) float value;
@end

it does make perfect sense to me, however, supposing I have a MyClass2 extending MyClass:

@interface MyClass2 : MyClass
@property (retain, readwrite) float value;
@end

so I have few questions, which I could easily answer if class extensions weren't involved:

  • at runtime, when in MyClass I am doing an assignment self.value=2 or just calling float x=self.value , which setter and getter @property are called ? MyClass or MyClass2 ?
  • shouldn't the compiler at least issue a warning about a readonly property being redefined ?
  • I know @property are backed by an ivar, so how many ivar are there in the end ? Related to this, calling the same self.value from MyClass2 point of view which ivar would set ?
¿Fue útil?

Solución

First off, the properties should be 'assign' not 'retain' since they are scalar types.

Changing the writability in class extensions or subclasses are common patterns to implement publicly read-only but privately writable properties and mutable subclasses of immutable classes, respectively. The Apple Objective-C Programming Guide has a good discussion.

To answer your first question, only methods declared in MyClass, or any of its super-classes, are visible from within MyClass. Your private class extension declares the setter in scope to the implementation, so that will get called. The readwrite declaration in the interface for MyClass2 merely brings the setter in to the public scope. The implementation is still in MyClass.

The answer to your second question is no, a warning is not issued. Changing writability from read-only to read-write is valid.

Finally, there is only one ivar. Accessing it from MyClass2 affects the same ivar visible in MyClass.

Otros consejos

You can't retain a float. Let's write (readonly) instead.

MyClass doesn't know anything about MyClass2, which seems to be a subclass of MyClass. When you write self.value = 2, it will be transformed into [self setValue:2] and the code will start at MyClass and look for a setValue method. This will have been created, because you defined value as a property. The setter method will look like

-(void) setValue:(int newValue) {
      _value = newValue; // _value is the actual storage for the property value
}

and the variable _value will be the one allocated in the instance of the object MyClass that you are executing.

In fact there is just one iVar. If, In MyClass2, you write

self.value = 3;
super.value = 4;
float myFloat = self.value;

myFloat ends up equal to 4.

Presumably the compiler doesn't complain about redefining the property in MyClass because it's quite a reasonable thing to do. That way, other classes cannot write to value, but within MyClass, you can write self.value = 2; and it will work.

I did believe there were two iVars, but I was wrong. Sorry for confusing anyone. Thanks to Martin R and BradS for educating me.

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