PayPal Here Message Bus Implementation
//
// PPHMessageBus.m
// PayPal Here
//
// Created by Matthew Pavlinsky on 9/11/12.
// Copyright (c) 2012 PayPal, Inc. All rights reserved.
//
#import "PPHMessageBus.h"
#import <objc/runtime.h>
#import "NINonRetainingCollections.h"
#pragma mark -
#pragma mark Private
// We all share this pointer.
static NSMutableSet *defaultResponders;
////////////////////////////////////////////////////////////////////////////////////////////////////
@interface PPHMessageBus () {
}
@property (nonatomic, assign) NSMutableSet *instanceResponders;
@property (nonatomic, assign) BOOL isTheAtLeastOneVersion;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation PPHMessageBus
#pragma mark -
#pragma mark Initialization
+(PPHMessageBus *)any
{
static dispatch_once_t pred;
static PPHMessageBus* shared = nil;
dispatch_once(&pred, ^{ shared = [[self alloc] initShared]; });
return shared;
}
+(PPHMessageBus*) atLeastOne
{
static dispatch_once_t pred;
static PPHMessageBus* shared = nil;
dispatch_once(&pred, ^{
shared = [[self alloc] initShared];
shared.isTheAtLeastOneVersion = YES;
});
return shared;
}
+ (PPHMessageBus*)sharedBus {
static dispatch_once_t pred;
static PPHMessageBus* shared = nil;
dispatch_once(&pred, ^{ shared = [[self alloc] initShared]; });
return shared;
}
-(id)initShared
{
self = [super init];
return self;
}
-(id)init
{
self = [super init];
if (self) {
self.instanceResponders = NICreateNonRetainingMutableSet();
}
return self;
}
+(void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defaultResponders = NICreateNonRetainingMutableSet();
});
}
#pragma mark -
#pragma mark Responder Registration
- (void)registerResponder:(id)responder {
NSMutableSet *responders = self.instanceResponders ?: defaultResponders;
@synchronized(responders) {
[responders addObject:responder];
}
}
- (void)unregisterResponder:(id)responder {
NSMutableSet *responders = self.instanceResponders ?: defaultResponders;
@synchronized(responders) {
[responders removeObject:responder];
}
}
-(BOOL)isRegsitered:(id)responder
{
NSMutableSet *responders = self.instanceResponders ?: defaultResponders;
@synchronized(responders) {
return [responders containsObject:responder];
}
}
#pragma mark -
#pragma mark Message forwarding
- (void)forwardInvocation:(NSInvocation *)invocation {
NSMutableSet *responders = self.instanceResponders ?: defaultResponders;
// Make a copy of the possible responders, so if a new responder is added as a byproduct of the invocation we don't crash.
NSSet* respondersSnapshot = nil;
@synchronized(responders) {
respondersSnapshot = [NSSet setWithSet:responders];
}
int count = 0;
for (id responder in respondersSnapshot) {
if ([responder respondsToSelector:invocation.selector]) {
[invocation invokeWithTarget:responder];
count++;
}
}
if (self.isTheAtLeastOneVersion && count == 0) {
NSAssert(FALSE, @"Expected at least one responder, got none. For invocation: %@ %@", invocation.target, NSStringFromSelector(invocation.selector));
}
}
- (NSSet *)respondersForProtocol:(Protocol *)protocol {
NSMutableSet *result = [NSMutableSet set];
NSMutableSet *responders = self.instanceResponders ?: defaultResponders;
@synchronized(responders) {
for (id responder in responders) {
if ([responder conformsToProtocol:protocol]) {
[result addObject:responder];
}
}
}
return result;
}
@end