TestsTested | ✗ |
LangLanguage | Obj-CObjective C |
License | BSD |
ReleasedLast Release | Dec 2014 |
Maintained by Unclaimed.
This is a library implementing futures in Objective-C, featuring:
TOCFuture
to represent eventual results, TOCCancelToken
to propagate cancellation notifications, TOCFutureSource
to produce and control an eventual result, and TOCCancelTokenSource
to produce and control a cancel token.[TOCFuture futureWithResult:[TOCFuture futureWithResult:@1]]
is automatically a [TOCFuture futureWithResult:@1]
.TOCCancelToken
passed to the operation's until:
or unless:
parameter.Recent Changes
Method #1: CocoaPods
pod 'TwistedOakCollapsingFutures', '~> 1.0'
pod install
from the project directory#import "CollapsingFutures.h"
wherever you want to use futures, cancel tokens, or their category methodsMethod #2: Manual
#import "CollapsingFutures.h"
wherever you want to use futures, cancel tokens, or their category methodsExternal Content
Using a Future
The following code is an example of how to make a TOCFuture
do something. Use thenDo
to make things happen when the future succeeds, and catchDo
to make things happen when it fails (there's also finallyDo
for cleanup):
#import "CollapsingFutures.h"
// ask for the address book, which is asynchronous because IOS may ask the user to allow it
TOCFuture *futureAddressBook = SomeUtilityClass.asyncGetAddressBook;
// if the user refuses access to the address book (or something else goes wrong), log the problem
[futureAddressBook catchDo:^(id error) {
NSLog("There was an error (%@) getting the address book.", error);
}];
// if the user allowed access, use the address book
[futureAddressBook thenDo:^(id arcAddressBook) {
ABAddressBookRef addressBook = (__bridge ABAddressBookRef)arcAddressBook;
... do stuff with addressBook ...
}];
Creating a Future
How does the asyncGetAddressBook
method from the above example control the future it returns?
In the simple case, where the result is already known, you use TOCFuture futureWithResult:
or TOCFuture futureWithFailure
.
When the result is not known right away, the class TOCFutureSource
is used. It has a future
property that completes after the source's trySetResult
or trySetFailure
methods are called.
Here's how asyncGetAddressBook
is implemented:
#import "CollapsingFutures.h"
+(TOCFuture *) asyncGetAddressBook {
CFErrorRef creationError = nil;
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &creationError);
// did we fail right away? Then return an already-failed future
if (creationError != nil) {
return [TOCFuture futureWithFailure:(__bridge_transfer id)creationError];
}
// we need to make an asynchronous call, so we'll use a future source
// that way we can return its future right away and fill it in later
TOCFutureSource *resultSource = [FutureSource new];
id arcAddressBook = (__bridge_transfer id)addressBookRef; // retain the address book in ARC land
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef requestAccessError) {
// time to fill in the future we returned
if (granted) {
[resultSource trySetResult:arcAddressBook];
} else {
[resultSource trySetFailure:(__bridge id)requestAccessError];
}
});
return resultSource.future;
}
Chaining Futures
Just creating and using futures is useful, but not what makes them powerful. The true power is in transformative methods like then:
and toc_thenAll
that both consume and produce futures. They make wiring up complicated asynchronous sequences look easy:
#import "CollapsingFutures.h"
+(TOCFuture *) sumOfFutures:(NSArray*)arrayOfFuturesOfNumbers {
// we want all of the values to be ready before we bother summing
TOCFuture* futureOfArrayOfNumbers = arrayOfFuturesOfNumbers.toc_thenAll;
// once the array of values is ready, add up its entries to get the sum
TOCFuture* futureSum = [futureOfArrayOfNumbers then:^(NSArray* numbers) {
double total = 0;
for (NSNumber* number in numbers) {
total += number.doubleValue;
}
return @(total);
}];
// this future will eventually contain the sum of the eventual numbers in the input array
// if any of the evetnual numbers fails, this future will end up failing as well
return futureSum;
}
The ability to setup transformations to occur once futures are ready allows you to write truly asynchronous code, that doesn't block precious threads, with very little boilerplate and intuitive propagation of failures.
How to Build:
Get Source Code: Clone this git repository to your machine.
Get Dependencies: Have cocoa pods installed. Run pod install
from the project directory.
Open Workspace: Open CollapsingFutures.xworkspace
with XCode (not the project, the workspace). Run tests and confirm that they pass.