148 lines · plain
1#import <Foundation/Foundation.h>2 3// SourceBase will be the base class of Source. We'll pass a Source object into a4// function as a SourceBase, and then see if the dynamic typing can get us through the KVO5// goo and all the way back to Source.6 7@interface SourceBase: NSObject8{9 uint32_t _value;10}11- (SourceBase *) init;12- (uint32_t) getValue;13@end14 15@implementation SourceBase16- (SourceBase *) init17{18 [super init];19 _value = 10;20 return self;21}22- (uint32_t) getValue23{24 return _value;25}26@end27 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 : SourceBase34{35 int _property;36}37- (Source *) init;38- (void) setProperty: (int) newValue;39@end40 41@implementation Source42- (Source *) init43{44 [super init];45 _property = 20;46 return self;47}48- (void) setProperty: (int) newValue49{50 _property = newValue; // This is the line in setProperty, make sure we step to here.51}52@end53 54@interface SourceDerived : Source55{56 int _derivedValue;57}58- (SourceDerived *) init;59- (uint32_t) getValue;60@end61 62@implementation SourceDerived63- (SourceDerived *) init64{65 [super init];66 _derivedValue = 30;67 return self;68}69- (uint32_t) getValue70{71 return _derivedValue;72}73@end74 75// Observer is the object that will watch Source and cause KVO to swizzle it...76 77@interface Observer : NSObject78{79 Source *_source;80}81+ (Observer *) observerWithSource: (Source *) source;82- (Observer *) initWithASource: (Source *) source;83- (void) observeValueForKeyPath: (NSString *) path 84 ofObject: (id) object85 change: (NSDictionary *) change86 context: (void *) context;87@end88 89@implementation Observer90 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 *) source100{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) object112 change: (NSDictionary *) change113 context: (void *) context114{115 printf ("Observer function called.\n");116 return;117}118@end119 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