Search code examples
iosobjective-cobserver-patternnsmutabledictionarykey-value-observing

Key Value Observe static NSDictionary on facade class


I have a ServiceFacade class with class methods for communicating with backend services. On that ServiceFacade class I have a static method that returns NSMutableDictionary in which I keep current ServiceFacade's downloading operations. I want to observer changes on this NSMutableDictionary either in AppDelegate or any other place. The app delegate seems not to respond to

- (void)addObserver:(NSObject *)anObserver
     forKeyPath:(NSString *)keyPath
        options:(NSKeyValueObservingOptions)options
        context:(void *)context{

}

Method for returning NSMutableDictionary:

    +(NSMutableDictionary *)downloadOperations
{
    if (_downloadOperations)
    {
        return _downloadOperations;
    }
    [_downloadOperations addObserver:[AppDelegate sharedAppDelegate] forKeyPath:@"downloadOperationsDict" options:0 context:NULL];
    _downloadOperations = [NSMutableDictionary dictionary];
    return _downloadOperations;
}

Any idea ?


Solution

  • There is no way to observe NSMutableDictionary changes. But there are 2 workarounds

    1) Subclass NSMutableDictionary and trigger Notifications on setObject:forKey and removeObjectForKey.
    2) Wrap your _downloadOperations write/remove operations and trigger notifications there.

    I suggest you to use 2) variant, as subclassing NSMutableDictionary is not so easy.

    So 2) variant will be like this.
    Add these 2 methods to class ServiceFacade

    - (void)setDownloadObject:(id)aObj forKey:(id<NSCopying>)aKey
    {
         [self.downloadOperations setObject:aObj forKey:aKey];
         [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadOperationsChanged" object:self
                                                               userInfo:self.downloadOperations];
    }
    
    - (id)removeDownloadObjectForKey:(id<NSCopying>)aKey
    {
         [[self.downloadOperations] removeObjectForKey:aKey];
         [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadOperationsChanged" object:self
                                                               userInfo:self.downloadOperations];
    }
    

    After this, you need to add and remove objects from that dictionary via this 2 methods. And you can also subscribe for changes

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(downloadOperationsChanged:)
                                                     name:@"DownloadOperationsChanged"
                                                   object:nil];
        return YES;
    }
    
    - (void)downloadOperationsChanged:(NSNotification *)aNotification
    {
        NSLog(@"Operations : %@", aNotification);
    }