Hi David! On 5. 8. 2012., at 23:08, David Chisnall <[email protected]> wrote:
> Hi Ivan, > > You seem to be very, very confused and none of the documentation that you > cite says what you seem to think it says. > > @dynamic does not mean run-time synthesized, it means the exact opposite, as > I said. @dynamic is just a hint to the compiler that you are providing the > implementation of the property (possibly in a superclass, possibly in a > category) and that it should not complain if it can't see one, nor should it > try to synthesise one if you are in a synthesis-by-default mode (recent > versions of clang default to synthesising properties if they don't see > implementations or @dynamic). > > And, as I suspected, you are confusing properties with KVC (Key-Value > Coding), or, perhaps more relevantly, with KVO (Key-Value Observing). > CoreAnimation makes heavy use of both KVC and KVO for animatable properties. > Note that the CoreAnimation documentation occasionally uses the term > 'properties' in the traditional way, rather than referring to declared > properties. > > For a property to be used for animation, it must be KVC-compliant, so that CA > can set it, and KVO compliant, so that CA can receive notifications when it > changes. Again, this does not require any method synthesis at run time. > > If you read the two links you posted carefully, then you will see that they > say nothing like what you seem to believe that they say. They explicitly > deal with the case where methods do not exist (@dynamic is used to ensure > that it does not), and so the first path in Core Animation fails. Trying to > animate a property with no corresponding setters and getters, CoreAnimation > will enter into one of the fall-back mechanisms, either one provided by > KVC/KVO or its own, which is very similar but a bit less general (and > therefore, in theory at least, faster). > > As I said before, you do not need to add methods at run time. You simply > need to implement the case when you try to set a property that does not have > a corresponding method. The Omni link explicitly tells you that this stuff > is all done using KVC... > > The examples use declared properties for simplicity, because they are using > it as a way of providing type information to KVC. I don't think our KVC > implementation actually makes use of property metadata in this way, so that's > something that you could look at fixing, although I think property > introspection only works with clang and the GNUstep runtime... > > David > Thanks for all the hints, however, I'm now even more confused. Some phrases such as this excerpt from Apple documentation (emphasis added) indicate that accessor methods are indeed synthesized at runtime: http://developer.apple.com/library/mac/#releasenotes/GraphicsImaging/CoreAnimation_RN/_index.html > Will now only synthesize property accessor methods for properties marked > @dynamic in their class implementation. For backwards compatibility we retain > the previous behavior for executables linked on OS versions prior to 10.6. I'd follow your advice and implement these properties via KVC/KVO, storing these additional properties in a dictionary, however that doesn't seem to be enough. Here's some quickly whipped-together test code. #import "ISAppDelegate.h" @interface LayerSubclass : CALayer @property (nonatomic, retain) NSString * prop; @end @implementation LayerSubclass @dynamic prop; @end @interface ObjectSubclass : NSObject @property (nonatomic, retain) NSString * prop; @end @implementation ObjectSubclass @dynamic prop; - (id)valueForKey:(NSString*)key { if([key isEqualToString:@"prop"]) return @"ok"; return [super valueForKey:key]; } - (void)setValue:(NSString*)value forKey:(NSString*)key { if([key isEqualToString:@"prop"]) { return; } return [super setValue:value forKey:key]; } @end void printMethods(id obj) { unsigned int count=0; Method * methodList = class_copyMethodList([obj class], &count); NSLog(@"%d methods:", count); for(int i = 0; i < count; i++) { NSLog(@" - %@", NSStringFromSelector(method_getName(methodList[i]))); } NSLog(@"------"); free(methodList); } @implementation ISAppDelegate - (void)dealloc { [super dealloc]; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { LayerSubclass * b = [LayerSubclass new]; printMethods(b); b.prop = @"5"; [b setProp:@"5"]; printMethods(b); ObjectSubclass * s = [ObjectSubclass new]; s.prop = @"5"; } @end Here's the output: 2012-08-06 10:46:06.112 SubclassingCALayerTest[4490:303] 0 methods: 2012-08-06 10:46:06.114 SubclassingCALayerTest[4490:303] ------ 2012-08-06 10:46:06.114 SubclassingCALayerTest[4490:303] 1 methods: 2012-08-06 10:46:06.115 SubclassingCALayerTest[4490:303] - setProp: 2012-08-06 10:46:06.116 SubclassingCALayerTest[4490:303] ------ 2012-08-06 10:46:06.117 SubclassingCALayerTest[4490:303] -[ObjectSubclass setProp:]: unrecognized selector sent to instance 0x101a27d80 2012-08-06 10:46:06.118 SubclassingCALayerTest[4490:303] -[ObjectSubclass setProp:]: unrecognized selector sent to instance 0x101a27d80 Obviously, CALayer has created accessor methods for the layer - even a direct message-send of setProp: works. In fact, the method appears to be created when the first attempt to access it is made. On the other hand, no hackery seems to be happening in NSObject subclass when setting the value of "prop". "setValue:forKey:" is not called - instead, the expected behavior of attempting to use the accessor "setProp:" occurs, and fails. Unless I'm misunderstanding again, I need to replicate the behavior of CALayer by adding accessor methods at runtime. I can do that in two ways: adding methods to the class at runtime, or intercepting an attempt to call an unknown method (via -forwardInvocation:). If I'm adding a method, it needs to be there; whether it's created in +initialize or in -forwardInvocation: doesn't really matter. No matter how I'm using forwarding mechanisms, I need to detect that it's an attempt to call an accessor. If you can point me at mistakes I made in the test code, or my understanding of the underlying mechanisms, I'd appreciate that. :-) -- Ivan Vučica
_______________________________________________ Discuss-gnustep mailing list [email protected] https://lists.gnu.org/mailman/listinfo/discuss-gnustep
