|
From: | Ivan Vučica |
Subject: | Re: @dynamic property synthesis |
Date: | Mon, 6 Aug 2012 10:51:19 +0200 |
Hi David! On 5. 8. 2012., at 23:08, David Chisnall <theraven@sucs.org> wrote: Hi Ivan, 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: 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 |
[Prev in Thread] | Current Thread | [Next in Thread] |