Skip to content

Instantly share code, notes, and snippets.

@epologee
Created January 24, 2011 19:13
Show Gist options
  • Save epologee/793751 to your computer and use it in GitHub Desktop.
Save epologee/793751 to your computer and use it in GitHub Desktop.
Simple Objective-C take on Robert Penner's Signals-AS3
//
// Signal.h
//
// Created by Eric-Paul Lecluse on 22-01-11.
// Copyright 2011 epologee. All rights reserved.
//
// This class was actually inspired and named by the brilliant work of Robert Penner & friends
// with the ActionScript 3.0 library called Signals: https://github.com/robertpenner/as3-signals
// It's not even close to a port, but it meets the demands of my current project.
#import <Foundation/Foundation.h>
@interface Signal : NSObject
-(void)add:(id)listener withSelector:(SEL)selector;
-(void)add:(id)listener withSelector:(SEL)selector oneShot:(BOOL)oneShot;
-(void)addTrigger:(Signal *)listener;
-(void)addTrigger:(Signal *)listener oneShot:(BOOL)oneShot;
-(void)removeAllListeners;
-(void)dispatch;
-(void)dispatchWithUserInfo:(NSDictionary *)userInfo;
@end
//
// Signal.m
//
// Created by Eric-Paul Lecluse on 22-01-11.
// Copyright 2011 epologee. All rights reserved.
//
#import "Signal.h"
@interface Signal ()
@property (nonatomic, retain) NSMutableSet *listeners;
@end
@implementation Signal
@synthesize listeners;
-(id) init {
self = [super init];
if (self) {
self.listeners = [[[NSMutableSet alloc] init] autorelease];
}
return self;
}
-(void) dealloc {
self.listeners = nil;
[super dealloc];
}
-(void)add:(id)listener withSelector:(SEL)selector {
[self add:listener withSelector:selector oneShot:NO];
}
-(void)add:(id)listener withSelector:(SEL)selector oneShot:(BOOL)oneShot {
NSArray *objects = [NSArray arrayWithObjects:listener, [NSValue valueWithPointer:selector], [NSNumber numberWithBool:oneShot], nil];
NSArray *keys = [NSArray arrayWithObjects:@"listener", @"selector", @"oneShot", nil];
[self.listeners addObject:[NSDictionary dictionaryWithObjects:objects forKeys:keys]];
}
-(void)addTrigger:(Signal *)listener {
[self addTrigger:listener oneShot:NO];
}
-(void)addTrigger:(Signal *)listener oneShot:(BOOL)oneShot {
NSArray *objects = [NSArray arrayWithObjects:listener, [NSNumber numberWithBool:oneShot], nil];
NSArray *keys = [NSArray arrayWithObjects:@"listener", @"oneShot", nil];
[self.listeners addObject:[NSDictionary dictionaryWithObjects:objects forKeys:keys]];
}
-(void)removeAllListeners {
[self.listeners removeAllObjects];
}
-(void)dispatch {
[self dispatchWithUserInfo:nil];
}
-(void)dispatchWithUserInfo:(NSDictionary *)userInfo {
NSMutableSet *remove = [[[NSMutableSet alloc] init] autorelease];
for (NSDictionary *listenerOptions in self.listeners) {
id listener = [listenerOptions objectForKey:@"listener"];
BOOL oneShot = [[listenerOptions objectForKey:@"oneShot"] boolValue];
if ([listener isKindOfClass:[Signal class]]) {
[listener dispatchWithUserInfo:userInfo];
} else {
SEL selector = [[listenerOptions objectForKey:@"selector"] pointerValue];
if ([listener respondsToSelector:selector]) {
NSMethodSignature *msig = [listener methodSignatureForSelector:selector];
if (msig != nil) {
NSUInteger nargs = [msig numberOfArguments];
if (nargs == 2) {
// The first two arguments are self and SEL
[listener performSelector:selector];
} else if (nargs == 3) {
// The third argument is actually the first parameter of the method.
// For now, this only works with userInfo NSDictionary objects.
[listener performSelector:selector withObject:userInfo];
} else {
// well yes, what else?
}
}
}
}
if (oneShot) {
[remove addObject:listenerOptions];
}
}
[self.listeners minusSet:remove];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment