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