1

It's an interview question. I know how to implement a non-block Notification Center with NSDictionary. But I have no idea how to implement a block NSNotification center because there is no "observer". Here is the code. Any idea?

#import <Foundation/Foundation.h>

/** LBNotificationCenter.h */

typedef void (^Observer)(NSString *name, id data);

@interface LBNotificationCenter : NSObject

- (void)addObserverForName:(NSString *)name block:(Observer)block;
- (void)removeObserverForName:(NSString *)name block:(Observer)block;
- (void)postNotification:(NSString *)name data:(id)data;

@end

/** LBNotificationCenter.m */

@interface LBNotificationCenter ()

@end

@implementation LBNotificationCenter

- (instancetype)init 
{
    self = [super init];
    if (self) {

    }
    return self;
}

- (void)addObserverForName:(NSString *)name block:(Observer)block 
{
      //add your code here
}

- (void)removeObserverForName:(NSString *)name block:(Observer)block 
{
       //add your code here
}

- (void)postNotification:(NSString *)name data:(id)data 
{
    //add your code here
}
Stanislav Pankevich
  • 11,044
  • 8
  • 69
  • 129
Rambo Li
  • 307
  • 1
  • 3
  • 16

2 Answers2

3

Blocks are normal objects so you can store them in NSArray/NSDictionary. Having that said the implementation is straightforward.

#import <Foundation/Foundation.h>

/** LBNotificationCenter.h */

typedef void (^Observer)(NSString *name, id data);

@interface LBNotificationCenter : NSObject

- (void)addObserverForName:(NSString *)name block:(Observer)block;
- (void)removeObserverForName:(NSString *)name block:(Observer)block;
- (void)postNotification:(NSString *)name data:(id)data;

@end

/** LBNotificationCenter.m */

@interface LBNotificationCenter ()
@property (strong, nonatomic) NSMutableDictionary <id, NSMutableArray <Observer> *> *observers;
@end

@implementation LBNotificationCenter

- (instancetype)init
{
    self = [super init];
    if (self) {
        _observers = [NSMutableDictionary new];
    }
    return self;
}

- (void)addObserverForName:(NSString *)name block:(Observer)block
{
    // check name and block for presence...

    NSMutableArray *nameObservers = self.observers[name];

    if (nameObservers == nil) {
        nameObservers = (self.observers[name] = [NSMutableArray new]);
    }

    [nameObservers addObject:block];
}

- (void)removeObserverForName:(NSString *)name block:(Observer)block
{
    // check name and block for presence...

    NSMutableArray *nameObservers = self.observers[name];

    // Some people might argue that this check is not needed
    // as Objective-C allows messaging nil
    // I prefer to keep it explicit
    if (nameObservers == nil) {
        return;
    }

    [nameObservers removeObject:block];
}

- (void)postNotification:(NSString *)name data:(id)data
{
    // check name and data for presence...

    NSMutableArray *nameObservers = self.observers[name];

    if (nameObservers == nil) {
        return;
    }

    for (Observer observer in nameObservers) {
        observer(name, data);
    }
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString *const Notification1 = @"Notification1";
        NSString *const Notification2 = @"Notification2";

        LBNotificationCenter *notificationCenter = [LBNotificationCenter new];

        Observer observer1 = ^(NSString *name, id data) {
            NSLog(@"Observer1 is called for name: %@ with some data: %@", name, data);
        };
        Observer observer2 = ^(NSString *name, id data) {
            NSLog(@"Observer2 is called for name: %@ with some data: %@", name, data);
        };

        [notificationCenter addObserverForName:Notification1 block:observer1];
        [notificationCenter addObserverForName:Notification2 block:observer2];

        [notificationCenter postNotification:Notification1 data:@"Some data"];
        [notificationCenter postNotification:Notification2 data:@"Some data"];

        [notificationCenter removeObserverForName:Notification1 block:observer1];

        // no observer is listening at this point so no logs for Notification1...
        [notificationCenter postNotification:Notification1 data:@"Some data"];

        [notificationCenter postNotification:Notification2 data:@"Some data"];
    }

    return 0;
}
Stanislav Pankevich
  • 11,044
  • 8
  • 69
  • 129
0

Why don't you just add the blocks into the NSDictionary ? You can do it like it's explained in this answer

Community
  • 1
  • 1
Julien Quere
  • 2,407
  • 16
  • 21
  • Yes you are right. I'm not familiar with both block and notification center. Thanks for your answer. – Rambo Li May 19 '16 at 00:25