KVUtils.m
author Jens Alfke <jens@mooseyard.com>
Sat Mar 28 09:39:31 2009 -0700 (2009-03-28)
changeset 21 88d7e2455a7f
parent 3 8fad19466c59
permissions -rw-r--r--
(merge)
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@3
    62
        [NSApp reportException: x];
jens@0
    63
    }
jens@0
    64
}
jens@0
    65
jens@0
    66
jens@0
    67
- (void)observeValueForKeyPath:(NSString *)keyPath 
jens@0
    68
                      ofObject:(id)object 
jens@0
    69
                        change:(NSDictionary *)change 
jens@0
    70
                       context:(void *)context
jens@0
    71
{
jens@0
    72
    if( object == _observed ) {
jens@0
    73
        if( _options & MYKeyValueObservingOptionDelayed )
jens@0
    74
            [self performSelector: @selector(_callTargetWithChange:) withObject: change
jens@0
    75
                       afterDelay: 0.0];
jens@0
    76
        else
jens@0
    77
            [self _callTargetWithChange: change];
jens@0
    78
        if( _options & MYKeyValueObservingOptionOnce )
jens@0
    79
            [self stopObserving];
jens@0
    80
    }
jens@0
    81
}
jens@0
    82
jens@0
    83
jens@0
    84
@end
jens@0
    85
jens@0
    86
jens@0
    87
jens@0
    88
jens@0
    89
@implementation Observer
jens@0
    90
jens@0
    91
jens@0
    92
- (id) init
jens@0
    93
{
jens@0
    94
    return [self initWithTarget: self];
jens@0
    95
}
jens@0
    96
jens@0
    97
jens@0
    98
jens@0
    99
- (id) initWithTarget: (id)target
jens@0
   100
{
jens@0
   101
    Assert(target);
jens@0
   102
    self = [super init];
jens@0
   103
    if (self != nil) {
jens@0
   104
        _target = target;
jens@0
   105
        _observances = [[NSMutableArray alloc] init];
jens@0
   106
    }
jens@0
   107
    return self;
jens@0
   108
}
jens@0
   109
jens@0
   110
jens@0
   111
- (void) dealloc
jens@0
   112
{
jens@0
   113
    [self stopObserving];
jens@0
   114
    [_observances release];
jens@0
   115
    [super dealloc];
jens@0
   116
}
jens@0
   117
jens@0
   118
jens@0
   119
@synthesize target=_target;
jens@0
   120
jens@0
   121
jens@0
   122
- (void) observe: (id)observed 
jens@0
   123
         keyPath: (NSString*)keyPath 
jens@0
   124
         options: (NSKeyValueObservingOptions)options
jens@0
   125
          action: (SEL)action
jens@0
   126
{
jens@0
   127
    Observance *o = [[Observance alloc] initWithTarget: _target
jens@0
   128
                                                action: action
jens@0
   129
                                              observed: observed
jens@0
   130
                                               keyPath: keyPath
jens@0
   131
                                               options: options];
jens@0
   132
    [_observances addObject: o];
jens@0
   133
    [o release];
jens@0
   134
}
jens@0
   135
jens@0
   136
jens@0
   137
- (void) observe: (id)observed 
jens@0
   138
         keyPath: (NSString*)keyPath 
jens@0
   139
          action: (SEL)action
jens@0
   140
{
jens@0
   141
    [self observe: observed keyPath: keyPath options: 0 action: action];
jens@0
   142
}
jens@0
   143
jens@0
   144
jens@0
   145
- (void) stopObserving
jens@0
   146
{
jens@0
   147
    [_observances makeObjectsPerformSelector: @selector(stopObserving)];
jens@0
   148
    [_observances removeAllObjects];
jens@0
   149
}
jens@0
   150
jens@0
   151
jens@3
   152
- (void) stopObserving: (id)observed
jens@3
   153
{
jens@3
   154
    [self stopObserving: observed keyPath: nil];
jens@3
   155
}
jens@3
   156
jens@3
   157
jens@0
   158
- (void) stopObserving: (id)observed keyPath: (NSString*)keyPath
jens@0
   159
{
jens@0
   160
    // observed or keyPath may be nil
jens@0
   161
    for( int i=_observances.count-1; i>=0; i-- ) {
jens@0
   162
        Observance *o = [_observances objectAtIndex: i];
jens@0
   163
        if( (observed==nil || observed==o.observed) && (keyPath==nil || [keyPath isEqual: o.keyPath]) ) {
jens@0
   164
            [o stopObserving];
jens@0
   165
            [_observances removeObjectAtIndex: i];
jens@0
   166
        }
jens@0
   167
    }
jens@0
   168
}
jens@0
   169
jens@0
   170
@end
jens@11
   171
jens@11
   172
jens@11
   173
/*
jens@11
   174
 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
jens@11
   175
 
jens@11
   176
 Redistribution and use in source and binary forms, with or without modification, are permitted
jens@11
   177
 provided that the following conditions are met:
jens@11
   178
 
jens@11
   179
 * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@11
   180
 and the following disclaimer.
jens@11
   181
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
jens@11
   182
 and the following disclaimer in the documentation and/or other materials provided with the
jens@11
   183
 distribution.
jens@11
   184
 
jens@11
   185
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@11
   186
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@11
   187
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@11
   188
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@11
   189
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@11
   190
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@11
   191
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@11
   192
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@11
   193
 */