Skip to content

Commit

Permalink
Merge pull request cappuccino#2261 from Dogild/CPNotificationBlock
Browse files Browse the repository at this point in the history
New: added method addObserverForName:object::usingBlock: in CPNotificationCenter
  • Loading branch information
primalmotion committed Nov 26, 2014
2 parents d5b4d66 + d481d9c commit e7ae969
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 7 deletions.
66 changes: 59 additions & 7 deletions Foundation/CPNotificationCenter.j
Expand Up @@ -68,7 +68,8 @@ var CPNotificationDefaultCenter = nil;
_namedRegistries = @{};
_unnamedRegistry = [[_CPNotificationRegistry alloc] init];
}
return self;

return self;
}

/*!
Expand All @@ -81,9 +82,36 @@ var CPNotificationDefaultCenter = nil;
*/
- (void)addObserver:(id)anObserver selector:(SEL)aSelector name:(CPString)aNotificationName object:(id)anObject
{
var registry,
var registry = [self _registryForNotificationName:aNotificationName],
observer = [[_CPNotificationObserver alloc] initWithObserver:anObserver selector:aSelector];

[registry addObserver:observer object:anObject];
}

/*!
Adds an entry to the receiver’s dispatch table with a block, and optional criteria: notification name and sender.
@param aNotificationName the name of the notification the observer wants to watch
@param anObject the object in the notification the observer wants to watch
@param queue is ignored for the moment
@param block the block to be executed when the notification is received.
*/
- (id <CPObject>)addObserverForName:(CPString)aNotificationName object:(id)anObject queue:(id)queue usingBlock:(Function)block
{
var registry = [self _registryForNotificationName:aNotificationName],
observer = [[_CPNotificationObserver alloc] initWithBlock:block];

[registry addObserver:observer object:anObject];

return observer;
}

/*!
@ignore
*/
- (_CPNotificationRegistry)_registryForNotificationName:(CPString)aNotificationName
{
var registry;

if (aNotificationName == nil)
registry = _unnamedRegistry;
else if (!(registry = [_namedRegistries objectForKey:aNotificationName]))
Expand All @@ -92,7 +120,7 @@ var CPNotificationDefaultCenter = nil;
[_namedRegistries setObject:registry forKey:aNotificationName];
}

[registry addObserver:observer object:anObject];
return registry;
}

/*!
Expand Down Expand Up @@ -233,7 +261,8 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
observersEnumerator = [observers objectEnumerator];

while ((observer = [observersEnumerator nextObject]) !== nil)
if ([observer observer] == anObserver)
if ([observer observer] == anObserver ||
([observer block] && [anObserver respondsToSelector:@selector(block)] && [observer block] == [anObserver block]))
[observers removeObject:observer];

if (![observers count])
Expand All @@ -248,7 +277,8 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
observersEnumerator = [observers objectEnumerator];

while ((observer = [observersEnumerator nextObject]) !== nil)
if ([observer observer] == anObserver)
if ([observer observer] == anObserver ||
([observer block] && [anObserver respondsToSelector:@selector(block)] && [observer block] == [anObserver block]))
[observers removeObject:observer];

if (![observers count])
Expand Down Expand Up @@ -312,8 +342,9 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
/* @ignore */
@implementation _CPNotificationObserver : CPObject
{
id _observer;
SEL _selector;
id _observer;
Function _block;
SEL _selector;
}

- (id)initWithObserver:(id)anObserver selector:(SEL)aSelector
Expand All @@ -327,13 +358,34 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
return self;
}

- (id)initWithBlock:(Function)aBlock
{
if (self)
{
_block = aBlock;
}

return self;
}

- (id)observer
{
return _observer;
}

- (id)block
{
return _block;
}

- (void)postNotification:(CPNotification)aNotification
{
if (_block)
{
_block(aNotification);
return;
}

[_observer performSelector:_selector withObject:aNotification];
}

Expand Down
45 changes: 45 additions & 0 deletions Tests/Foundation/CPNotificationCenterTest.j
Expand Up @@ -52,6 +52,51 @@ var TestNotification = @"TestNotification";
[self assert:8 equals:notificationCount message:@"observer should not be notified"];
}

- (void)testNotifyWithBlocks
{
var center = [CPNotificationCenter defaultCenter];

notificationCount = 0;

var notificationBlock = function(notification){
notificationCount += 1;
};

var observer2 = [center addObserverForName:TestNotification object:2 queue:nil usingBlock:notificationBlock],
observer25 = [center addObserverForName:TestNotification object:25 queue:nil usingBlock:notificationBlock];

[center postNotificationName:TestNotification object:self];
[self assert:0 equals:notificationCount message:@"observer should only be notified for object '2'"];

[center postNotificationName:TestNotification object:2];
[self assert:1 equals:notificationCount message:@"observer should be notified for object '2'"];

var observerNil = [center addObserverForName:TestNotification object:nil queue:nil usingBlock:notificationBlock];

[center postNotificationName:TestNotification object:2];
[self assert:3 equals:notificationCount message:@"observer should be notified for object '2' and for any object"];

[center removeObserver:observer2 name:TestNotification object:2];
[center postNotificationName:TestNotification object:2];
[self assert:4 equals:notificationCount message:@"observer should be notified only for any object"];

// At this point we have TestNofication:nil observer and a TestNotification:25 observer.
observer2 = [center addObserverForName:nil object:2 queue:nil usingBlock:notificationBlock];

[center postNotificationName:TestNotification object:2];
[self assert:6 equals:notificationCount message:@"observer should be notified for TestNofication and for object '2' (TestNotification)"];
[center postNotificationName:@"RandomNotification" object:2];
[self assert:7 equals:notificationCount message:@"observer should be notified for object '2' (RandomNotification)"];

[center removeObserver:observer2];
[center removeObserver:observer25];
[center removeObserver:observerNil];
[center postNotificationName:TestNotification object:nil];
[center postNotificationName:TestNotification object:2];
[center postNotificationName:TestNotification object:25];
[self assert:7 equals:notificationCount message:@"observer should not be notified"];
}

- (void)testAddObserversDuringNotification
{
var center = [CPNotificationCenter defaultCenter];
Expand Down

0 comments on commit e7ae969

Please sign in to comment.