1 #import <Foundation/Foundation.h> 2 3 // SourceBase will be the base class of Source. We'll pass a Source object into a 4 // function as a SourceBase, and then see if the dynamic typing can get us through the KVO 5 // goo and all the way back to Source. 6 7 @interface SourceBase: NSObject 8 { 9 uint32_t _value; 10 } 11 - (SourceBase *) init; 12 - (uint32_t) getValue; 13 @end 14 15 @implementation SourceBase 16 - (SourceBase *) init 17 { 18 [super init]; 19 _value = 10; 20 return self; 21 } 22 - (uint32_t) getValue 23 { 24 return _value; 25 } 26 @end 27 28 // Source is a class that will be observed by the Observer class below. 29 // When Observer sets itself up to observe this property (in initWithASource) 30 // the KVO system will overwrite the "isa" pointer of the object with the "kvo'ed" 31 // one. 32 33 @interface Source : SourceBase 34 { 35 int _property; 36 } 37 - (Source *) init; 38 - (void) setProperty: (int) newValue; 39 @end 40 41 @implementation Source 42 - (Source *) init 43 { 44 [super init]; 45 _property = 20; 46 return self; 47 } 48 - (void) setProperty: (int) newValue 49 { 50 _property = newValue; // This is the line in setProperty, make sure we step to here. 51 } 52 @end 53 54 @interface SourceDerived : Source 55 { 56 int _derivedValue; 57 } 58 - (SourceDerived *) init; 59 - (uint32_t) getValue; 60 @end 61 62 @implementation SourceDerived 63 - (SourceDerived *) init 64 { 65 [super init]; 66 _derivedValue = 30; 67 return self; 68 } 69 - (uint32_t) getValue 70 { 71 return _derivedValue; 72 } 73 @end 74 75 // Observer is the object that will watch Source and cause KVO to swizzle it... 76 77 @interface Observer : NSObject 78 { 79 Source *_source; 80 } 81 + (Observer *) observerWithSource: (Source *) source; 82 - (Observer *) initWithASource: (Source *) source; 83 - (void) observeValueForKeyPath: (NSString *) path 84 ofObject: (id) object 85 change: (NSDictionary *) change 86 context: (void *) context; 87 @end 88 89 @implementation Observer 90 91 + (Observer *) observerWithSource: (Source *) inSource; 92 { 93 Observer *retval; 94 95 retval = [[Observer alloc] initWithASource: inSource]; 96 return retval; 97 } 98 99 - (Observer *) initWithASource: (Source *) source 100 { 101 [super init]; 102 _source = source; 103 [_source addObserver: self 104 forKeyPath: @"property" 105 options: (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) 106 context: NULL]; 107 return self; 108 } 109 110 - (void) observeValueForKeyPath: (NSString *) path 111 ofObject: (id) object 112 change: (NSDictionary *) change 113 context: (void *) context 114 { 115 printf ("Observer function called.\n"); 116 return; 117 } 118 @end 119 120 uint32_t 121 handle_SourceBase (SourceBase *object) 122 { 123 return [object getValue]; // Break here to check dynamic values. 124 } 125 126 int main () 127 { 128 Source *mySource; 129 Observer *myObserver; 130 131 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 132 133 mySource = [[SourceDerived alloc] init]; 134 myObserver = [Observer observerWithSource: mySource]; 135 136 [mySource setProperty: 5]; // Break here to see if we can step into real method. 137 138 uint32_t return_value = handle_SourceBase (mySource); 139 140 SourceDerived *unwatchedSource = [[SourceDerived alloc] init]; 141 142 return_value = handle_SourceBase (unwatchedSource); 143 144 [pool release]; 145 return 0; 146 147 } 148