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 | |