Skip to content

Commit

Permalink
Merge pull request #28 from uber/artman/swift
Browse files Browse the repository at this point in the history
Adds default implementations for default signal types using concrete signal classes.
  • Loading branch information
artman committed Apr 12, 2016
2 parents 138c847 + 44ac9f1 commit 3f95e38
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 17 deletions.
2 changes: 1 addition & 1 deletion UberSignals.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'UberSignals'
s.version = '2.4.0'
s.version = '2.5.0'
s.license = { :type => 'MIT' }
s.summary = 'Signals is an eventing framework that enables you to implement the Observable pattern without using NSNotifications.'
s.homepage = 'https://github.com/uber/signals-ios'
Expand Down
6 changes: 5 additions & 1 deletion UberSignals/UBBaseSignal.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

typedef void (^UBSignalObserverChange)(UBSignalObserver *signalObserver);

/**
Expand All @@ -41,4 +43,6 @@ typedef void (^UBSignalObserverChange)(UBSignalObserver *signalObserver);
- (void)removeObserver:(NSObject *)observer;
- (void)removeAllObservers;

@end
@end

NS_ASSUME_NONNULL_END
4 changes: 4 additions & 0 deletions UberSignals/UBSignal+Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface UBBaseSignal()

- (void)removeSignalObserver:(UBSignalObserver *)signalObserver;
- (BOOL)firePastDataForSignalObserver:(UBSignalObserver *)signalObserver;

@end

NS_ASSUME_NONNULL_END
4 changes: 4 additions & 0 deletions UberSignals/UBSignal+Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

NS_ASSUME_NONNULL_BEGIN

#ifndef PP_NARG

#define PP_NARG(...) \
Expand Down Expand Up @@ -94,3 +96,5 @@ NO_WARN_FOR_INCOMPLETE_IMPLEMENTATION_END
@protocol UBSignalArgumentCount3 @end
@protocol UBSignalArgumentCount4 @end
@protocol UBSignalArgumentCount5 @end

NS_ASSUME_NONNULL_END
46 changes: 45 additions & 1 deletion UberSignals/UBSignal.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

/**
Creates a new Signal type.
Expand Down Expand Up @@ -84,8 +86,36 @@ CreateSignalType(Dictionary, NSDictionary *dictionary);
/** An Signal type that fires a NSMutableDictionary */
CreateSignalType(MutableDictionary, NSMutableDictionary *mutableDictionary);

/** An Signal type that fires an Integer as a NSNumber */
CreateSignalInterface(UBIntegerSignal, NSNumber *number);

/** An Signal type that fires a Float as a NSNumber */
CreateSignalInterface(UBFloatSignal, NSNumber *number);

/** An Signal type that fires an Double as a NSNumber */
CreateSignalInterface(UBDoubleSignal, NSNumber *number);

/** An Signal type that fires an Boolean as a NSNumber */
CreateSignalInterface(UBBooleanSignal, NSNumber *number);

/** An Signal type that fires an NSString */
CreateSignalInterface(UBStringSignal, NSString *string);

/** An Signal type that fires an NSArray */
CreateSignalInterface(UBArraySignal, NSArray *array);

/** An Signal type that fires a NSMutableArray */
CreateSignalInterface(UBMutableArraySignal, NSMutableArray *mutableArray);

/** An Signal type that fires a NSDictionary */
CreateSignalInterface(UBDictionarySignal, NSDictionary *dictionary);

/** An Signal type that fires a NSMutableDictionary */
CreateSignalInterface(UBMutableDictionarySignal, NSMutableDictionary *mutableDictionary);


/**
A Signal represents a type of event that Observable objects implement and fire and Observers listen to.
A Signal represents a type of event that Observable objects implement and fire and Observers listen to.
Each class that wants to implement the Observable pattern first register the types of events they fire using the CreateSignalType macro. This registers the type of data that is being fired by one of the Signals of the class to ensure type-safety.
Expand Down Expand Up @@ -167,3 +197,17 @@ CreateSignalType(MutableDictionary, NSMutableDictionary *mutableDictionary);
- (instancetype)init NS_UNAVAILABLE;

@end

/**
A special type of signal that doesn't have any parameters.
*/
@interface UBEmptySignal : UBBaseSignal <UBSignalArgumentCount0>

- (UBSignalObserver *)addObserver:(id)observer callback:(void (^)(id self))callback; \
- (void (^)())fire;
- (void (^)(UBSignalObserver *signalObserver))fireForSignalObserver;
- (instancetype)initWithProtocol:(Protocol *)protocol NS_UNAVAILABLE;

@end

NS_ASSUME_NONNULL_END
23 changes: 23 additions & 0 deletions UberSignals/UBSignal.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@

#import "UBSignalObserver+Internal.h"

CreateSignalImplementation(UBIntegerSignal, NSNumber *number);
CreateSignalImplementation(UBFloatSignal, NSNumber *number);
CreateSignalImplementation(UBDoubleSignal, NSNumber *number);
CreateSignalImplementation(UBBooleanSignal, NSNumber *number);
CreateSignalImplementation(UBStringSignal, NSString *string);
CreateSignalImplementation(UBArraySignal, NSArray *array);
CreateSignalImplementation(UBMutableArraySignal, NSMutableArray *mutableArray);
CreateSignalImplementation(UBDictionarySignal, NSDictionary *dictionary);
CreateSignalImplementation(UBMutableDictionarySignal, NSMutableDictionary *mutableDictionary);

@implementation UBSignal : UBBaseSignal

Expand All @@ -42,3 +51,17 @@ - (instancetype)initWithProtocol:(Protocol *)protocol {
}

@end


#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincomplete-implementation"

@implementation UBEmptySignal

- (instancetype)init {
self = [super initWithProtocol:@protocol(UBSignalArgumentCount0)];
return self;
}
#pragma clang diagnostic pop

@end
4 changes: 4 additions & 0 deletions UberSignals/UBSignalObserver+Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#import "UBSignal+Internal.h"

NS_ASSUME_NONNULL_BEGIN

typedef void (^UBSignalCallback) (id listener, ...);
typedef void (^UBSignalCallbackArgCount1) (id listener, id arg1);
typedef void (^UBSignalCallbackArgCount2) (id listener, id arg1, id arg2);
Expand All @@ -44,3 +46,5 @@ typedef void (^UBSignalCallbackArgCount5) (id listener, id arg1, id arg2, id arg
- (instancetype)initWithSignal:(UBBaseSignal *)signal observer:(id)observer callback:(UBSignalCallback)callback;

@end

NS_ASSUME_NONNULL_END
4 changes: 4 additions & 0 deletions UberSignals/UBSignalObserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

/**
A SignalObserver is returned whenever an observer is added to a UBSignal. Use it to cancel this specific observation or change the OperationQueue on which to dispatch the callback on.
*/
Expand Down Expand Up @@ -52,3 +54,5 @@
- (void)cancel;

@end

NS_ASSUME_NONNULL_END
67 changes: 67 additions & 0 deletions UberSignalsTests/SwiftTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,73 @@ import XCTest

class SwiftTests: XCTestCase {

func testEmptyObservation() {
var observed = 0
let observer = UBSignalEmitter()

observer.onEmptySignalSwift.addObserver(self) { (listener) in
observed += 1
}

observer.onEmptySignalSwift.fire()()

XCTAssertEqual(observed, 1, "Should have fired callback")
}

func testPredefinedSignals() {
var observed = 0

let signal = UBDictionarySignal()
signal.addObserver(self) { (listener) in
observed += 1
}
signal.fire()(Dictionary())

let signal2 = UBArraySignal()
signal2.addObserver(self) { (listener, result) in
XCTAssertEqual(result, NSArray(objects: "result"), "Should have signaled correct result")
observed += 1
}
signal2.fire()(["result"])

let signal3 = UBFloatSignal()
signal3.addObserver(self) { (listener, result) in
XCTAssertEqual(result, 20.0, "Should have signaled correct result")
observed += 1
}
signal3.fire()(20.0)

let signal4 = UBDoubleSignal()
signal4.addObserver(self) { (listener, result) in
XCTAssertEqual(result, 20.0, "Should have signaled correct result")
observed += 1
}
signal4.fire()(20.0)

let signal5 = UBBooleanSignal()
signal5.addObserver(self) { (listener, result) in
XCTAssertEqual(result, true, "Should have signaled correct result")
observed += 1
}
signal5.fire()(true)

let signal6 = UBIntegerSignal()
signal6.addObserver(self) { (listener, result) in
XCTAssertEqual(result, 10, "Should have signaled correct result")
observed += 1
}
signal6.fire()(10)

let signal7 = UBMutableDictionarySignal()
signal7.addObserver(self) { (listener, result) in
XCTAssertEqual(result, NSMutableDictionary(), "Should have signaled correct result")
observed += 1
}
signal7.fire()(NSMutableDictionary())

XCTAssertEqual(observed, 7, "Should have fired callback")
}

func testObservation() {
var observed = 0
let observer = UBSignalEmitter()
Expand Down
1 change: 1 addition & 0 deletions UberSignalsTests/UBSignalEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ CreateSignalInterface(UBSwiftDoubleSignal, NSString *stringData, NSNumber *numbe
@interface UBSignalEmitter : NSObject

@property (nonatomic, readonly) UBSignal<EmptySignal> *onEmptySignal;
@property (nonatomic, readonly) UBEmptySignal *onEmptySignalSwift;
@property (nonatomic, readonly) UBSignal<IntegerSignal> *onIntegerSignal;
@property (nonatomic, readonly) UBSignal<TupleSignal> *onStringSignal;
@property (nonatomic, readonly) UBSignal<TripleSignal> *onTripleSignal;
Expand Down
1 change: 1 addition & 0 deletions UberSignalsTests/UBSignalEmitter.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ -(instancetype)init
self = [super init];
if (self) {
_onEmptySignal = (UBSignal<EmptySignal> *)[[UBSignal alloc] initWithProtocol:@protocol(EmptySignal)];
_onEmptySignalSwift = [[UBEmptySignal alloc] init];
_onIntegerSignal = (UBSignal<IntegerSignal> *)[[UBSignal alloc] initWithProtocol:@protocol(IntegerSignal)];
_onStringSignal = (UBSignal<TupleSignal> *)[[UBSignal alloc] initWithProtocol:@protocol(TupleSignal)];
_onTripleSignal = (UBSignal<TripleSignal> *)[[UBSignal alloc] initWithProtocol:@protocol(TripleSignal)];
Expand Down
14 changes: 0 additions & 14 deletions UberSignalsTests/UBSignalTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -625,13 +625,6 @@ - (void)testAllArgumentCounts
XCTAssertThrows([signal addObserver:self callback:^(id self) {}], @"Should have complained about max observers");
}

- (void)testObservingWithoutCallback
{
UBSignal<EmptySignal> *signal = (UBSignal<EmptySignal> *)[[UBSignal alloc] initWithProtocol:@protocol(EmptySignal)];
XCTAssertThrows([signal addObserver:nil callback:^(id self) {}], @"Should have complained about nil observer");
XCTAssertThrows([signal addObserver:self callback:nil], @"Should have complained about nil callback");
}

- (void)testRemovingListenerWhileInObserverCallback {
UBSignalEmitter *emitter = [[UBSignalEmitter alloc] init];

Expand Down Expand Up @@ -732,11 +725,4 @@ - (void)testDebugDescription
XCTAssert([[signal debugDescription] containsString:@"<UBSignalObserver: "], @"Should contain string");
}

- (void)testAddingInvalidObservers
{
UBSignal<EmptySignal> *signal = (UBSignal<EmptySignal> *)[[UBSignal alloc] initWithProtocol:@protocol(EmptySignal)];
XCTAssertThrows([signal addObserver:nil callback:^(id self) {}], @"Should have asserted");
XCTAssertThrows([signal addObserver:self callback:nil], @"Should have asserted");
}

@end

0 comments on commit 3f95e38

Please sign in to comment.