I'm running into an odd quirk involving Core Data, a declared protocol, and perhaps the LLVM 1.5 compiler. Here's the situation.
I have a Core Data model that among others has two classes, IPContainer and IPEvent, with IPContainer being the parent entity of IPEvent. Each entity has a custom class in the project for it, created using mogenerator. mogenerator generates an additional subclass that just contains the modeled property declarations, so the class hierarchy is actually IPEvent > _IPEvent > IPContainer > _IPContainer > NSManagedObject. The IPContainer entity has an attribute named 'id', which is declared as @property(nonatomic, retain) NSNumber* id;
in _IPContainer.h. _IPContainer.m has @dynamic id;
in the implementation, to tell Core Data to generate the accessors at runtime
I also have a protocol IPGridViewGroup declared in my project which defines several properties, one of which is that same 'id' property. However, a setter is not necessary for classes implementing this protocol, so the property in the protocol is declared as @property(readonly) NSNumber* id;
The IPEvent class declares that it conforms to the IPGridViewGroup protocol.
This worked fine using the Clang/LLVM 1.0.x compiler (whichever version shipped with Xcode 3.2.2), but upon upgrading to Xcode 3.2.3 and Clang/LLVM 1.5, a whole bunch of things changed. First, I get the following warning when compiling the IPEvent class:
/Volumes/Ratbert/Users/bwebster/Projects/UberProject/iPhotoLibraryManager/IPGridViewGroup.h:19:31: warning: property 'id' requires method 'id' to be defined - use @synthesize, @dynamic or provide a method implementation
Then, when I actually run the program, this gets printed out in the console:
Property 'id' is marked readonly on class 'IPEvent'. Cannot generate a setter method for it.
Followed shortly by:
-[IPEvent setId:]: unrecognized selector sent to instance 0x200483900
I also tried redeclaring the property on the IPEvent class, but that just gave me a different compiler warning, and the same behavior at runtime:
/Volumes/Ratbert/Users/bwebster/Projects/UberProject/iPhotoLibraryManager/IPManagedObject/IPEvent.h:14:40: warning: property 'id' 'retain' attribute does not match the property inherited from 'IPGridViewGroup'
Now, the only thing that's changed here is the compiler, so the catalyst for the change is clear, but what I don't know is whether this could be considered a bug in the new version of the compiler, or if the old version of the compiler was actually behaving incorrectly, and the new version now reveals that it's my own code that's buggy.
So among the questions I have here are:
- It seems like it should be OK to have a class conform to a protocol with a readonly property, but provide readwrite access for the property in its own implementation, is that correct? The quirk here though is that the readwrite property is actually declared in the superclass of the class that conforms to the protocol.
- I'm assuming that console message is being printed out somewhere in the bowels of Core Data. This is odd though, because IPEvent itself doesn't declare the 'id' property explicity, except by conforming to the IPGridViewGroup protocol. However, if this is the case, then I would think a compiler error would come up, since it would effectively being overriding a readwrite property (declared in the _IPContainer superclass) with a readonly version of the same property, which AFAIK is normally not allowed.
- If this is a compiler bug, then fine, I can work around it in a couple different ways for now. If the compiler is doing the right thing here though, then I'm at a loss to come up with a way to organize all this so I don't get any compiler warnings or runtime errors.
Edit: so, the workaround is to redeclare the property again on the IPEvent class, but I'm still puzzled as to why the two versions of the compiler act differently. It's also unclear how exactly properties declared on a protocol are supposed to interact with those declared on a class.
If I declare a readonly property in the class (rather than the protocol) overriding a readwrite property, I get the message "warning: attribute 'readonly' of property 'longitude' restricts attribute 'readwrite' of property inherited from '_IPEvent'". It seems like if declaring it in the protocol has the same effect, a similar warning should come up from the compiler.
Intuitively though, I would think that since IPEvent already implements the necessary getter for the property, that should count as "conforming to the protocol", even if it happens to also implement a setter for the property.