author | Jens Alfke <jens@mooseyard.com> |
Wed Apr 02 14:45:33 2008 -0700 (2008-04-02) | |
changeset 2 | 3d3dcc3116d5 |
child 3 | 8fad19466c59 |
permissions | -rw-r--r-- |
jens@0 | 1 |
// |
jens@0 | 2 |
// KVUtils.m |
jens@0 | 3 |
// MYUtilities |
jens@0 | 4 |
// |
jens@0 | 5 |
// Created by Jens Alfke on 2/25/08. |
jens@0 | 6 |
// Copyright 2008 Jens Alfke. All rights reserved. |
jens@0 | 7 |
// |
jens@0 | 8 |
|
jens@0 | 9 |
#import "KVUtils.h" |
jens@0 | 10 |
|
jens@0 | 11 |
|
jens@0 | 12 |
@implementation Observance |
jens@0 | 13 |
|
jens@0 | 14 |
- (id) initWithTarget: (id)target |
jens@0 | 15 |
action: (SEL)action |
jens@0 | 16 |
observed: (id)observed |
jens@0 | 17 |
keyPath: (NSString*)keyPath |
jens@0 | 18 |
options: (NSKeyValueObservingOptions)options |
jens@0 | 19 |
{ |
jens@0 | 20 |
self = [super init]; |
jens@0 | 21 |
if (self != nil) { |
jens@0 | 22 |
_target = target; |
jens@0 | 23 |
_action = action; |
jens@0 | 24 |
_observed = observed; |
jens@0 | 25 |
_keyPath = [keyPath copy]; |
jens@0 | 26 |
_options = options; |
jens@0 | 27 |
|
jens@0 | 28 |
options &= ~(MYKeyValueObservingOptionOnce | MYKeyValueObservingOptionDelayed); |
jens@0 | 29 |
|
jens@0 | 30 |
[_observed addObserver: self forKeyPath: _keyPath options: options context: _action]; |
jens@0 | 31 |
} |
jens@0 | 32 |
return self; |
jens@0 | 33 |
} |
jens@0 | 34 |
|
jens@0 | 35 |
- (void) dealloc |
jens@0 | 36 |
{ |
jens@0 | 37 |
[_observed removeObserver: self forKeyPath: _keyPath]; |
jens@0 | 38 |
[_keyPath release]; |
jens@0 | 39 |
[super dealloc]; |
jens@0 | 40 |
} |
jens@0 | 41 |
|
jens@0 | 42 |
|
jens@0 | 43 |
@synthesize observed=_observed, keyPath=_keyPath; |
jens@0 | 44 |
|
jens@0 | 45 |
|
jens@0 | 46 |
- (void) stopObserving |
jens@0 | 47 |
{ |
jens@0 | 48 |
[_observed removeObserver: self forKeyPath: _keyPath]; |
jens@0 | 49 |
_observed = nil; |
jens@0 | 50 |
_target = nil; |
jens@0 | 51 |
_action = NULL; |
jens@0 | 52 |
} |
jens@0 | 53 |
|
jens@0 | 54 |
|
jens@0 | 55 |
- (void) _callTargetWithChange: (NSDictionary*)change |
jens@0 | 56 |
{ |
jens@0 | 57 |
@try{ |
jens@0 | 58 |
[_target performSelector: _action withObject: _observed withObject: change]; |
jens@0 | 59 |
}@catch( NSException *x ) { |
jens@0 | 60 |
Warn(@"Uncaught exception in -[%@<%p> %s] while observing change of key-path %@ in %@<%p>: %@", |
jens@0 | 61 |
_target,_target, _action, _keyPath, _observed,_observed, x); |
jens@0 | 62 |
} |
jens@0 | 63 |
} |
jens@0 | 64 |
|
jens@0 | 65 |
|
jens@0 | 66 |
- (void)observeValueForKeyPath:(NSString *)keyPath |
jens@0 | 67 |
ofObject:(id)object |
jens@0 | 68 |
change:(NSDictionary *)change |
jens@0 | 69 |
context:(void *)context |
jens@0 | 70 |
{ |
jens@0 | 71 |
if( object == _observed ) { |
jens@0 | 72 |
if( _options & MYKeyValueObservingOptionDelayed ) |
jens@0 | 73 |
[self performSelector: @selector(_callTargetWithChange:) withObject: change |
jens@0 | 74 |
afterDelay: 0.0]; |
jens@0 | 75 |
else |
jens@0 | 76 |
[self _callTargetWithChange: change]; |
jens@0 | 77 |
if( _options & MYKeyValueObservingOptionOnce ) |
jens@0 | 78 |
[self stopObserving]; |
jens@0 | 79 |
} |
jens@0 | 80 |
} |
jens@0 | 81 |
|
jens@0 | 82 |
|
jens@0 | 83 |
@end |
jens@0 | 84 |
|
jens@0 | 85 |
|
jens@0 | 86 |
|
jens@0 | 87 |
|
jens@0 | 88 |
@implementation Observer |
jens@0 | 89 |
|
jens@0 | 90 |
|
jens@0 | 91 |
- (id) init |
jens@0 | 92 |
{ |
jens@0 | 93 |
return [self initWithTarget: self]; |
jens@0 | 94 |
} |
jens@0 | 95 |
|
jens@0 | 96 |
|
jens@0 | 97 |
|
jens@0 | 98 |
- (id) initWithTarget: (id)target |
jens@0 | 99 |
{ |
jens@0 | 100 |
Assert(target); |
jens@0 | 101 |
self = [super init]; |
jens@0 | 102 |
if (self != nil) { |
jens@0 | 103 |
_target = target; |
jens@0 | 104 |
_observances = [[NSMutableArray alloc] init]; |
jens@0 | 105 |
} |
jens@0 | 106 |
return self; |
jens@0 | 107 |
} |
jens@0 | 108 |
|
jens@0 | 109 |
|
jens@0 | 110 |
- (void) dealloc |
jens@0 | 111 |
{ |
jens@0 | 112 |
[self stopObserving]; |
jens@0 | 113 |
[_observances release]; |
jens@0 | 114 |
[super dealloc]; |
jens@0 | 115 |
} |
jens@0 | 116 |
|
jens@0 | 117 |
|
jens@0 | 118 |
@synthesize target=_target; |
jens@0 | 119 |
|
jens@0 | 120 |
|
jens@0 | 121 |
- (void) observe: (id)observed |
jens@0 | 122 |
keyPath: (NSString*)keyPath |
jens@0 | 123 |
options: (NSKeyValueObservingOptions)options |
jens@0 | 124 |
action: (SEL)action |
jens@0 | 125 |
{ |
jens@0 | 126 |
Observance *o = [[Observance alloc] initWithTarget: _target |
jens@0 | 127 |
action: action |
jens@0 | 128 |
observed: observed |
jens@0 | 129 |
keyPath: keyPath |
jens@0 | 130 |
options: options]; |
jens@0 | 131 |
[_observances addObject: o]; |
jens@0 | 132 |
[o release]; |
jens@0 | 133 |
} |
jens@0 | 134 |
|
jens@0 | 135 |
|
jens@0 | 136 |
- (void) observe: (id)observed |
jens@0 | 137 |
keyPath: (NSString*)keyPath |
jens@0 | 138 |
action: (SEL)action |
jens@0 | 139 |
{ |
jens@0 | 140 |
[self observe: observed keyPath: keyPath options: 0 action: action]; |
jens@0 | 141 |
} |
jens@0 | 142 |
|
jens@0 | 143 |
|
jens@0 | 144 |
- (void) stopObserving |
jens@0 | 145 |
{ |
jens@0 | 146 |
[_observances makeObjectsPerformSelector: @selector(stopObserving)]; |
jens@0 | 147 |
[_observances removeAllObjects]; |
jens@0 | 148 |
} |
jens@0 | 149 |
|
jens@0 | 150 |
|
jens@0 | 151 |
- (void) stopObserving: (id)observed keyPath: (NSString*)keyPath |
jens@0 | 152 |
{ |
jens@0 | 153 |
// observed or keyPath may be nil |
jens@0 | 154 |
for( int i=_observances.count-1; i>=0; i-- ) { |
jens@0 | 155 |
Observance *o = [_observances objectAtIndex: i]; |
jens@0 | 156 |
if( (observed==nil || observed==o.observed) && (keyPath==nil || [keyPath isEqual: o.keyPath]) ) { |
jens@0 | 157 |
[o stopObserving]; |
jens@0 | 158 |
[_observances removeObjectAtIndex: i]; |
jens@0 | 159 |
} |
jens@0 | 160 |
} |
jens@0 | 161 |
} |
jens@0 | 162 |
|
jens@0 | 163 |
@end |