Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
convenience methods to notify a deferred of the
result of another deferred without affecting the result of the other deferred
  • Loading branch information
JimRoepcke committed May 14, 2012
1 parent 423ece5 commit d12792e
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
2 changes: 2 additions & 0 deletions HLDeferred/Classes/HLDeferred.h
Expand Up @@ -45,6 +45,7 @@ typedef void (^HLVoidBlock)(void);

+ (HLDeferred *) deferredWithResult: (id)result;
+ (HLDeferred *) deferredWithError: (id)error;
+ (HLDeferred *) deferredObserving: (HLDeferred *)otherDeferred;

- (HLDeferred *) then: (ThenBlock)cb;
- (HLDeferred *) fail: (FailBlock)eb;
Expand All @@ -62,6 +63,7 @@ typedef void (^HLVoidBlock)(void);

- (HLDeferred *) takeResult: (id)aResult;
- (HLDeferred *) takeError: (id)anError;
- (HLDeferred *) notify: (HLDeferred *)otherDeferred;
- (void) cancel;

@end
23 changes: 23 additions & 0 deletions HLDeferred/Classes/HLDeferred.m
Expand Up @@ -88,6 +88,13 @@ @implementation HLDeferred
+ (HLDeferred *) deferredWithResult: (id)aResult { return [[[[self alloc] init] autorelease] takeResult: aResult]; }
+ (HLDeferred *) deferredWithError: (id)anError { return [[[[self alloc] init] autorelease] takeError: anError]; }

+ (HLDeferred *) deferredObserving: (HLDeferred *)otherDeferred
{
HLDeferred *result = [[[self alloc] init] autorelease];
[otherDeferred notify: result];
return result;
}

- (id) initWithCanceller: (id <HLDeferredCancellable>) theCanceller
{
self = [super init];
Expand Down Expand Up @@ -204,6 +211,22 @@ - (HLDeferred *) takeError: (id)anError
return self;
}

// this is different than chaining. The result from the other
// HLDeferred's callback chain will not affect this HLDeferred's result.
// this is useful if you cache a HLDeferred and don't want its result
// mutated by its clients. Instead, return a new HLDeferred that is
// notified by the cached HLDeferred.
// Also, check out the convenience method: +deferredObserving:
//
// return [HLDeferred deferredObserving: _cachedDeferred];
//
- (HLDeferred *) notify: (HLDeferred *)otherDeferred
{
// NSLog(@"%@ in %@", self, NSStringFromSelector(_cmd));
return [self then: ^(id result) { [otherDeferred takeResult: result]; return result; }
fail: ^(HLFailure *failure) { [otherDeferred takeError: failure]; return failure; }];
}

- (void) cancel
{
if (! called_) {
Expand Down
41 changes: 41 additions & 0 deletions HLDeferred/Tests/HLDeferredTest.m
Expand Up @@ -183,6 +183,47 @@ - (void) testPausing
[d2 release];
}

- (void) testNotifying
{
HLDeferred *d1 = [[HLDeferred alloc] init];
HLDeferred *d2 = [[HLDeferred alloc] init];

[d1 then: ^(id result) {
GHAssertEqualStrings(@"starting", result, nil);
return @"d1-result";
}];

[d1 notify: d2];

[d2 then: ^(id result) {
GHAssertEqualStrings(@"d1-result", result, nil);
return @"d2-result-after-d1-notified-d2";
}];

[d1 then: ^(id result) {
GHAssertEqualStrings(@"d1-result", result, nil);
return result;
}];

[d2 then: ^(id result) {
GHAssertEqualStrings(@"d2-result-after-d1-notified-d2", result, nil);
return result;
}];

[d1 takeResult: @"starting"];

HLDeferred *d3 = [HLDeferred deferredObserving: d2];
GHAssertNotNil(d3, nil);

[d3 then:^ (id result) {
GHAssertEqualStrings(@"d2-result-after-d1-notified-d2", result, nil);
return result;
}];

[d1 release];
[d2 release];
}

- (void) testCancel
{
HLDeferredTestCanceller *c = [[HLDeferredTestCanceller alloc] init];
Expand Down

0 comments on commit d12792e

Please sign in to comment.