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