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 120uint32_t 121handle_SourceBase (SourceBase *object) 122{ 123 return [object getValue]; // Break here to check dynamic values. 124} 125 126int 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