Altconf michael gray facebook

How I Learned to Stop Worrying and Love the GCD

An overview of Futures/Promises in Swift and specifically FutureKit, and how to use it to never have to call dispatch_async again. A brief introduction to asynchronous handling and how a Futures/Promises implementation library will help.

We will cover the basics:

  • How to build a Promise/Future pair.
  • How to use Executors to make the GCD simple.
  • Never write another function with a callback block property again.
  • How to wrap all your favorite async libraries into Futures (like AlamoFire, ReactiveCocoa, etc).
  • Create rock solid error handling, and dead simple cancellations.

I will also give a brief overview of Futures based coding patterns like caching, parallel execution, NSOperationQueues, FIFO based execution, etc.


Introduction (0:00)

My name’s Michael Gray. Currently I am the tech lead of a startup, Ambulnz.com. We are hiring, so if you want an exciting career in a medical transportation business, which is actually way more exciting than you would think, and you are good at iOS or Node, you should talk to me.

I’m going to talk to you about FutureKit. It’s not the only Futures-Promises implementation on Swift, but it’s one that I think is more “swifty” than many of the others. We’re going to talk about what the heck these things are, and why nobody can actually be consistent about them.

Then we’ll talk a bit about the FutureKit, which is a little bit different than the others but a lot of those differences are style. You’ll figure out whether you like it or not, but you should at least be looking at some of the differences.

Before we talk about Futures and Promises and what they are, we have to talk about blocks and closures.

Blocks & Closures (2:09)

What’s nice about your blocks and closures is they can get rid of all those nasty delegate protocols. There are some delegate protocols you can’t get rid of, but you’ll notice more and more, you can now just define a function with a callback block. If you looked at the GCD, the Grand Central Dispatcher, and you have to do things not in the main thread, you do them with blocks.

Now we’re going to start talking about how terrible they are.


func asyncFunction(callback:(Result) -> Void) -> Void {

	dispatch_async(queue) {
		let x = Result("Hello!")
		callback(x)
	}
}

So this is a typical case. It’s my asyncFunction, I’ve got some sort of result, but if I want to get the result back, then I have to supply a callback routine.

If you’ve been writing enough asynchronous stuff, you’ve probably already written this before. I have my example here where, for whatever reason, we have to dispatch into a background queue, and then we generate our result and then we callback.

The rise of the callback block (3:42)

As a matter of fact, I’ll talk a bit about AFNetworking. I think AFNetworking became number one in the iOS library because it eliminated the horrible delegate protocols that existed in the NSURL. It’s all callback based.


Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
	.response { request, response, data, error in
		print(request)
		print(response)
		print(data)
		print(error)
}

This is in Alamofire, the latest version of it that’s working. I’m not here to put anything down about Alamofire. I love it, but this is probably one of the best examples of use of callback blocks, where you’re going to issue a request to get. I get some kind of response object, and you’ll see these nice options–request, response, data, error–as all of the things that might happen to this asynchronous API lookup call.

All right, what’s wrong? There are problems. When you execute a function with a callback block, weird little things crop up. Like where the heck does the callback run?

Once you start writing for asynchronous coding, you can no longer write in the main thread, because if you write in the main thread your app stutters and you have to get things into the background. So you’re executing a callback function, that itself is in the background, but then it’s going to call you back, but where is it going to call you back? Does the callback block now have to be dispatched into the MainQ? But what if I don’t even want the result in the MainQ?

Another issue is, how the heck are we doing error handling? Do I supply two callbacks? I’ve seen APIs that have one callback for a success, and one callback for fail. I just showed you in that example, why more people are using nice Swift enumerations instead, which is better, if you’re going to do that. But it’s still an issue, how can you scope with errors?

Then there’s cancellation. Another thing that was inconsistent for years, in all these libraries, is that if I have an operation, and I cancel it, do you call my callback or do you not? And then, how do I deal with it?


func getMyDataObject(url: NSURL,callback:(object:MyCoreDataObject?,error: ErrorType) ->
Void) {
	Alamofire.request(.GET, url, parameters: ["foo": "bar"]).responseJSON { response in
		switch response.result {
		case .Success:
			managedContext.performBlock {
				let myObject = MyCoreDataObject(entity: entity!,
					insertIntoManagedObjectContext: managedContext)
				do {
					try myObject.addData(response)
					try managedContext.save()
					dispatch_async(dispatch_get_main_queue(), {
						callback(object: myObject, error: nil)
					})
				} catch let error {
					callback(object: nil,error: error)
				}
			}
		case .Failure(let error):
			callback(object: nil,error: error)
		}
	}
}

Here’s a typical function, written in standard GCD callback. I have my Alamofire request, that I’m going to get. I have a response with a nice enumeration, this is a good practice.

Again, I’m showing Alamofire not because I don’t like it. I think it’s actually the best-written callback library out there, but we’ll start seeing where it’s weak.

Now I’m going to get my response. If it’s successful, this is an API call that I want to go to some server and return a model object. We’re going to do my Alamofire with this URL, assuming I get a successful response.

I’m going to go to my managed object context and do the performBlock, because the managed object context is in a different context, because I want to make sure that I’m not writing in the main thread. I’m going to use a background process.

Let’s call the performBlock. Now I’m in another dispatch, so now I’m going to say okay, let’s make MyCoreDataObject, and now I have my little addData method, which I’m going to allow it to return an error.

Get more development news like this

We’re going to do some good Swift error handling here, because maybe what I got back from the server wasn’t good or the JSON wasn’t validated. Then I’m going to save to Core Data because that might throw errors.

Lastly, because I’m a good citizen, and I know that I’m in a background thread, I don’t want to return the result in my Core Data’s queue, I’m going to bring this back to the MainQ.

By using this API call it’s going to help my programmers make fewer mistakes. Once they start, they’re going to start modifying views, and they better be doing that in the main thread. So I’m going to do this dispatch_async. If I have an error, then I have to return an error type.

This is already three interactions of callback, that you can see in here. You could get to five or six, and bad things start happening.

Why Futures & Promises (7:50)

So what in the heck are these Futures and Promises, and why are people using them? These are basically designed to get you out of callback hell.

We use a lot of JavaScript Promises which work really well. What’s the difference between a Future and a Promise? Their job is to get you out of callback hell, that’s their primary job.

Why are there two words here, and when do I use one and when do I use the other? There’s no consistency in any of the implementations that I’ve seen. JavaScript just calls things Promises, but JavaScript isn’t type-specific, so it can be a little bit easier. There are implementations that just use the term Future, because in theory, all of this can be done in a single object.

I stole the FutureKit implmentation from Scala. Again, this is a choice, but they’re basically all very similar. For FutureKit, we use the Future object in the consumer interface. That means that this is what you’re probably going to be returning from functions.

If you’re defining like functions, the Future is what you give to the consumer of your API, and a Promise is the low-level way that you have to generate a Future. I like the word Promise, because when you create a Promise, you have to keep your Promises. If you create one and you hand out a Future, you’d better complete it, otherwise your code will just stop mysteriously.


func getMyDataObject(url: NSURL) -> Future<MyCoreDataObject> {
	let executor = Executor.ManagedObjectContext(managedContext)

	Alamofire.request(.GET, url, parameters: ["foo": "bar"])
		.FutureJSONObject()
		.onSuccess(executor) { response -> MyCoreDataObject in
			let myObject = MyCoreDataObject(entity: entity!,
				insertIntoManagedObjectContext: managedContext)
			try myObject.addData(response)
			try managedContext.save()
			return MyCoreDataObject
		}
	}
}

This is the same function that we saw earlier. This is written in FutureKit.

First off, you’ll see the signature at the top is very different, now there’s no callback. It’s just, what data do I need, and I get back this Future MyCoreDataObject. Notice the lack of optional MyCoreDataObject. It is just MyCoreDataObject.

There is an executor that I’m creating here. This is another FutureKit thing which I’m creating based on a ManagedObjectContext. This is wrapping, if you have ever done any Core Data, it basically wraps that performBlock for you.

Now I have my Alamofire request, and there’s this FutureJSONObject that is out of the Alamofire extension. FutureKit Alamofire extensions will convert the response object from Alamofire into a Future.

Now I can say, onSuccess(executor) which means, this block is now running inside of my performBlock. If you notice the nice signature here, there’s a response that I got, in what is my response object, and I’m just going to return the Core Data object.

Now I have my try. Notice there’s no do or catch. It’s mysteriously absent from the handler. Now I can just hit try to add some data, try to save my thing and just return the object.

The idea here is that this function has returned to this object called a Future, and the Future has these little handlers.

Primary handler: onComplete (11:30)

The primary handler in FutureKit is what’s called onComplete. If you understand the onComplete handler, you’ll understand how every other handler in FutureKit is really working. Every other handler you’ll ever see is just convenience wrappers around this one.


let newFuture = sampleFuture.onComplete { (result: FutureResult<Int>) ->
Completion<String> in
	switch result {

	case let .Success(value):
		return .Success(String(value))

	case let .Fail(err):
		return .Fail(err)

	case .Cancelled:
		return .Cancelled
	}
}

I’m calling onComplete and I’m getting back this enumerated object called a FutureResult. Again, these are generic, so this is a Future result of some kind of integer, and I am going to map that to a Completion. And I’ll talk about what those two things are.


public enum FutureResult<T> {
	case Success(T)
	case Fail(ErrorType)
	case Cancelled
}

The first one is the FutureResult. This is basically every Future, when it’s finally done. This is what it spits out.

Now, unlike a lot of the other Futures implementations that produce a result, FutureKit actually adds this enumeration called Cancelled. We’ll talk about Cancelled, and why it is promoted and not just Success or `Fail’, like what you’ll see in a lot of other asynchronous implementations.


public enum Completion<T> {
	case Success(T)
	case Fail(ErrorType)
	case Cancelled
	case CompleteUsing(Future<T>)
}

There’s this other enumeration called a Completion. Completions seem very confusing at first, but they’re really not.

The easiest way to think of a Completion, is it is a thing that completes a Future. You can assign it to a Promise, and it looks a lot like the result, but it has this extra enumeration which says, I would really rather have you complete this Promise from some other Promise. That becomes very powerful when we start doing composing. In this onComplete, you can actually see that.


	case let .Success(value):
		return .Success(String(value))

	case let .Fail(err):
		return .Fail(err)

Those are actually two different enumerations. The first one is a result, and the second one is a completion.

Most of the time, you’re not going to call onComplete. You only need to call it in exceptions. Most people are just going to call onSuccess.


let asyncFuture5 = Future(.Background) { () -> Int in
	return 5
}
let f = asyncFuture5.onSuccess(.Main) { (value) -> Int in
	let five = value
	print("\(five)")
	return five
}

Here’s a typical example of how you would build in FutureKit. I’ve created a Future in my first line. This is the cheap and easy way to create a Future. It’s using this .Background, which we will get to later, that’s this interesting executor thing.

I’m saying I want to create a Future, in the background, that generates the number five. For some reason, it’s expensive, and I want to do this in the background, so I’m going to generate a Future. It returns a five, so now I’m in my onSuccess.

Now I can say, onSuccess I want to make sure I’m doing this in the main thread, because I’m going to do some I/O. I’m going to take that value and I’m going to print it out. Now, this value, this is the type, no enumeration, it’s the actual thing that you’re looking for, this is it.


let stringFuture = Future<String>(success: "5")

stringFuture
    .onSuccess { (stringResult:String) -> Int in
        let i = Int(stringResult)!
        return i
    }
    .map { intResult -> [Int] in
        let array = [intResult]
        return array
    }
    .onSuccess { arrayResult -> Int? in
        return arrayResult.first!
    }

You can now take an onSuccess, and you can take one Future and map it into a different Future.

Assume I have some stringFuture that I got from a function. This is a notation for creating a completed Future. This is a Future that returns a string, that’s already completed with a success.

I’m going to then say in the first block, when I have an onSuccess, I want to take a string to an Int. The Swift compiler does nice type inferences and will automatically know that in the next .map, which is really just the alternate way of saying onSuccess, if you prefer the word map.

Now I’m going to map that integer result into an array of Ints. Basically, there’s this idea that you can take any Future and immediately map it into more and more Futures. Notice how this is flat, and you’ll see this sort of indentation style that crops up if you do a lot of functional Reactive programming. It’s very similar, it’s not identical, but again, nice and flat with no callbacks.


func coolFunctionThatAddsOneInBackground(num : Int) -> Future<Int> {
	// let's dispatch this to the low priority background queue
	return Future(.Background) { () -> Int in
		let ret = num + 1
		return ret
	}
}

let stringFuture = Future<Int>(success: 5)

stringFuture
	.onSuccess { intResult -> Future<Int> in
      return coolFunctionThatAddsOneInBackground(intResult)
	}
	.onSuccess {
      return coolFunctionThatAddsOneInBackground($0)
	}

The big advantage of Futures over say, other kinds of interfaces, is that they are highly-composable. This is a slightly more detailed example.

I have this nice cool function that can actually add numbers in the background. I’m going to go into the background, and I’m going to add my numbers, because again, it’s expensive and we don’t want to do it in the main thread. Now, if you notice, I’ve got the stringFuture, that same stringFuture from before, but what I’m going to do is, I’m going to return, not a new value, but I’m actually going to return another Future. You can map a Future, either to a value or to another Future.

Futures and Promises make things very easy to compose. All Futures, Promises, implementations that are anything, they all tend to have a structure. This is where things get really cool.

What is a Promise? (16:47)

So what is a Promise? Let’s say you have a library in which you want to create a Future. I create a Promise, this is a Promise that’s going to return an array of strings. Now I have a nice array of strings that I found, which I’m calling completeWithSuccess.


let namesPromise = Promise<[String]>()

let names = ["Skyler","David","Jess"]
namesPromise.completeWithSuccess(names)

let namesFuture :Future<[String]> = namesPromise.Future

namesFuture.onSuccess(.Main) { (names : [String]) -> Void in
	for name in names {
		print("Happy Future Day \(name)!")
	}
}

This is basically saying, I am completing the Promise, the Promise is successful, and here is the result. You’ll notice all Promises have this member called .Future. And that’s the Future that you can return, that is the way that you generate this consumer interface for your Promise. Now I can actually execute this Promise.


func getCoolCatPic(catUrl: NSURL) -> Future<UIImage> {

	let catPicturePromise = Promise<UIImage>()

	let task = NSURLSession.sharedSession().dataTaskWithURL(catUrl) { (data, response, error) ->
Void in
		if let e = error {
			catPicturePromise.completeWithFail(e)
		}
		else {
			if let d = data, image = UIImage(data: d) {
				catPicturePromise.completeWithSuccess(image)
			}
			else {
				catPicturePromise.completeWithErrorMessage("didn't understand response from \
(response)")
			}
		}
	}
	task.resume()
	
	// return the Promise's Future.
	return catPicturePromise.Future
}

Typically, when you need Promises is when you’ve got one of these things you have to wrap that takes a callback. If you’re using libraries that use callbacks, you can Future-ize them, convert them into Futures, but with a Promise.

This is a typical example, this comes out of the playground that’s inside of FutureKit, where I’m going to go get some cool cat pictures. This is not as cool in this slide, because in the playground, you actually see the cat, but here you just have to Promise that there is one.

I want a function which, given a URL, will return an image. If you think about it, to get an image object, I both have to go to the internet and get the data object from my networking layer, I have to convert the data object into a UI image, and then I have to place it back. All of that is going to be encapsulated here.

I’m using the standard NSURL session. It has my URL, and now I get all of these callback responses. I get the data that came back, the response object and the error, and now I can start parsing it.

If I receive an error, I’m going to complete my Promise with a fail. If I receive data, and I can convert that data into an image, then I am succesful. If that fails and I don’t want to create a custom error type, there’s a built-in one that we says “I couldn’t understand this response”. I’ll start the NSURL session and now I can return this Future.

If you think about the way this would run, this whole block inside would execute later, but the Future can be returned to immediately. You can see how you can wrap this thing.

What about error handling (19:23)

Let’s consider errors and error handling. This is where I think Futures are always great, because often if you’re doing everything right, you just don’t have to think about, and it usually just works fine.

When you’re doing callbacks, for every single callback API that you’re wrapping, you have to check for errors. You have to check for errors a lot. I didn’t even include those steps into the callback hell too much because it just makes it worse.

For example, you’re going to have to make an API call. Then I get all these networking errors. Maybe I get a JSON object back from my server, so maybe my JSON parsing issues are failing, maybe there’s a validation problem. Now I’m going to go and take that, once I’ve parsed it, I’m going to save it to the database. Then I’m going to get file-I/O issues, or there could be database-validation errors.

Any one of these errors could occur. I want one nice high-level API call to my users, to just go get me this thing, and everything else can fail. What happens in Futures, is if you’re doing everything right, anyone of those Futures is going to pipe right up to the top.

FutureKit does not let you define error-type specific Futures. When you try to create error specific type Futures, it actually undermines the very composability that you saw earlier. Because now you have to filter all of your composability with map an error, map this error, to map that error. It actually ends up that what you thought would be better, it actually worse now.

The other thing about FutureKit is because it’s not error-type specific, you’ll also notice that there is no ErrorType. They always talk about allowing you to create a FutureKit that would not return an error, but again, what we found is that that actually undermines composability. The whole idea of something being asynchronous means that it may or may not succeed. If today it’s no error, then later it might produce an error. When it comes to these kinds of Futures, it’s better to not have the no-error condition.

You’ll see in FutureKit right now, if you create a Future chain and you fail to put an error handler at the end, you’ll get a compiler warning. It will tell you, “hey, you called a Future, and I don’t see any way that you could handle any errors”.

The other thing that’s nice about FutureKit, is all of these handlers that you’ll see: the onComplete, onSuccess, onFail. They all have a built-in catch. You do not have to wrap any of these methods, any do or catch. If you’ve got a method in Swift and you’re calling try, don’t worry about it. Just say try, and the Future that you’re composing inside of that thing will automatically fail with that error.


func getMyDataObject(url: NSURL) -> Future<MyCoreDataObject> {
	let executor = Executor.ManagedObjectContext(managedContext)

	Alamofire.request(.GET, url)
		.FutureJSONObject()
		.onSuccess(executor) { response -> MyCoreDataObject in
			let myObject = MyCoreDataObject(entity: entity,
							insertIntoManagedObjectContext: managedContext)
			try myObject.addData(response)
			try managedContext.save()
			return MyCoreDataObject
		}.onFail { error in
			// alert user of error!
	}
}

There is this nice onFail handler that you’ll see now. I went back to my little example and I added the onFail handler, because if I compile the old code, I get my compiler warning. Now I’m going to add my whatever side effects.

There’s another difference that we’re doing at FutureKit, versus some of the other ones. Our onFail handler doesn’t consume errors. This is unlike if you’ve done JavaScript, and you call catch, catch is great because you not want to look at the error. But it also consumes the error, which means that if you’re writing it inside of a function, people forget that you want to add a side effect for the error. But yours still failed.

The default in FutureKit is you add handlers for the failures, but because you’re writing functions that are asynchronous, we usually understand that you’re probably going to have to fail that function anyway. The default value on onFail was for handling failures, but not for say, catching them. So you don’t pass them up; you have to use onComplete within FutureKit.

This is basically a design choice, and there were earlier implementations where onFail would let you do more, but I just don’t trust my developers.

You now know that when you see that onComplete, somebody could actually be mucking with the meanings, like taking a failed Future and turning it into a successful Future. That turns out to be only 10% of cases. 90% of the time, if something failed, you want to be able to clean up and then notify.

Cancellations (24:21)

Now, the other big thing you’ll see in FutureKit is cancellations. This is anytime you have an asynchronous operation. You might start it and then later, you realize you don’t need the result. You may not even want those handlers to get executed because they’re meaningless now, because whatever the request was, you’re opening your view, you’re going to fetch from the internet whatever content you need, and then the guy hits close, and he closes his view controller. Then you still have all this asynchronous stuff going on underneath. This is your opportunity to clean it up.

There is an onCancel handler which you can now add. When I need to know that things have been cancelled, we usually use onComplete. FutureKit does cancellation really well. It’s the one piece of code that if you look on GitHub, and look at how it works, it’s actually really hard.

Here’s a function that returns a Future:


let f = asyncFunc1().onSuccess {
	return asyncFunc2()
}
let token = f.getCancelToken()
token.cancel()

This function has been composed with an onSuccess that then returns a second Future. The question is, that if I call cancel on this, am I cancelling asyncFunc1 or am I cancelling asyncFunc2?

It cancels both. It will cancel one, and then, if that one’s actually already completed, you don’t have to worry about it. If you need to implement cancellation, that’s very easy. There’s a handler on your Promise to basically say, I want a cancellable Future. This is your opportunity to be told that your Future’s being canceled, and you can clean up your stuff.


let p = Promise<Void>()

p.onRequestCancel { (options) ->
CancelRequestResponse<Void> in
	// start cancelling
	return .Continue
}

There’s actually an enumerator response, where you can either declare that you don’t want to cancel the Future yet, because I still have to wait for cleanup, or I might want to just cancel the Future right away.


public extension AlamoFire.Request {
	public func Future<T: ResponseSerializerType>(responseSerializer s: T) -> Future<T.SerializedObject> {
		let p = Promise<T.SerializedObject>()
		p.onRequestCancel { _ in
			self.cancel()
			return .Continue
		}
		self.response(queue: nil, responseSerializer: s) { response -> Void in
			switch response.result {
			case let .Success(t):
				p.completeWithSuccess(t)
			case let .Failure(error):
				let e = error as NSError
				if (e.domain == NSURLErrorDomain) && (e.code == NSURLErrorCancelled) {
					p.completeWithCancel()
				}
				else {
					p.completeWithFail(error)
				}
			}
		}
		return p.Future
	}
}

You can do either one in the handler. I’m going to go back to this nice little example I ripped out from the Alamofire FutureKit extension wrapper. I leaked in all this Alamofire serialization stuff. This is the generic that lets me turn any Alamofire serializer into a Future.

The very first thing I do is create a Promise around whatever you’re trying to serialize, and then I add the cancellation handler. I edit first and then I’m mapping my response here.

I’m saying, if I get a cancellation, I’m going to call this the self.cancel, that’s the built-in Alamofire request cancel, and I say, just keep running. Then you’ll see it on here where I’m looking at the error result. I’m actually realizing that this error is a cancellation, and I’m going to complete that with cancellation.

The new Swift anti-patterns (27:39)

Once you understand the basics of writing Futures, you start looking at your code and you realize there’s a whole set of new anti-patterns. You’ll see it in people’s code and go, “Oh, oh, stop doing that.”

One of them is any function with a callback property. They just start to hurt when you see them. Another thing that you’ll start seeing, another thing that I notice is that, especially as people start using Futures, is they’ll by default, create Futures with optional results. Typically, that’s not the point. You don’t need the optional results anymore.

Like in the callbacks, your callback methods would have the optional result, because you might get the result or you might get the error. If you couldn’t make the object, if you couldn’t make the result fail, that’s the right composition.

Another thing that’s really important that you can do with any good Futures implementation, is if I need operations that are run in the background, now it can be the job of the function itself, to define its own execution context.

So if I’ve got an imaging library, and I want to make sure it’s not running in the main thread, I don’t have to make the consumer of my API worry about that. I can just say go compute it, and then function itself can dispatch into the right place to execute. We’ll talk about how that works next.

Executors (29:07)

So the other big piece in FutureKit is this term of executors. In other languages’ Futures implementations, it might be called ExecutionContext. This was sort of inspired by the Bolts Executors.

The FutureKit executor is actually an enumeration. As you’ll notice, FutureKit loves enumerations. The executor class in FutureKit has a set of enumerated values that mirror the built-in GCD. 80% or 90% of the time, you just use a built-in Grand Central Dispatch. Right away, I received a number of numbers that mirror these names.


let asyncFuture5 = Future(.Background) { () -> Int in
	return 5
}
let f = asyncFuture5.onSuccess(.Main) { (value) -> Int in
	let five = value
	print("\(five)")
	return five
}

This is where I think FutureKit has a nice, efficient design. I’m going to create a Future and I want it to run in the background, and I execute it. Same way on all these onSuccesses. I can add an executor.

There’s actually a bunch of executors. There are some special ones. There’s what I call the .Immediate executor. The immediate executor means, I don’t really care where my block’s going to run. I can run anywhere. Those are usually the efficient one. This might be all you’re doing. Mapping. Maybe you’re just taking an integer, and you’re converting to a string and you don’t really care. You don’t re-dispatch to anything.

There’s the .MainImmediate, which means that I would like to be on the MainQ, but don’t, if the code is already running on the MainQ. Just do it now, if not, dispatch to the MainQ. There’s the .MainAsync, which is always an async dispatch. Maybe you’re in a weird delegate, and you have to let the delegate finish, but you need the code to run.

Then there’s a couple of others that crop up, for example, you’ve already got your own dispatch queue, you can wrap that in an executor. You can wrap an NS operation queue into an executor. You can wrap a managed object context in an executor, if you’re ever wrestling with perform block operations.

There’s some extra smart ones, I call these extra smart because they actually figure out one or the other. You declare them in your code and they map to something else at run time. The smartest is called the .Current. If you’re already in an executor, just stay in it. This is the actual default, because it turns out that programmers, as you start getting in it, they get lazy. They start out in the background, and they want to stay in the background.

Well, if you’ve wrapped your execution in an executor, if you don’t give FutureKit an executor, it’ll just try to figure out. Who’s calling this? What execution context is it in? I will make sure that the callback will automatically go into that execution context, even if the method underneath has decided to go into the background.

Then there’s the .Primary. The .Primary is the executor that executes what you don’t tell us, what executor you want, which by default. These last four are all configurable, they’re all some FutureKit operations.

The one that I tend to use is this .Async, which means, I want to be in the background somewhere, and maybe later on decide I’ll change the QoS for my default operations.

Then there’s actually a .Custom, and the .Custom lets you build your own. The example we have is an executor that, let’s say I’ve got an operation that I want, it needs to run in the MainQ, but I want to maybe spend some time in the background queue, because it’s not critically important.

We’ve got some weird examples where you could create an executor, that dispatches to the background, which waits for things to be idle, and then it re-dispatches back to the MainQ.


let ex: Executor = .Background

let f = ex.execute {
	let data = expensiveToComputeData()
	return data
}

Executors also have a nice execute method, which is another cheap way of making a Future. If you notice here, I’ve created a background executor and I’m calling its execute method. I’m calling some method that computes data expensively, and I’m just going to return the data. There’s also a few other executes with delays and things.


let shiftFuture = model.getShift()
let vehicleFuture = model.getVehicle()

combineFutures(shiftFuture, vehicleFuture)
	.onSuccess { (shift,vehicle) -> Void in
		print("\(shift),\(vehicle)")
}

The next thing we have is the combined Futures. This is a case where we need parallel executions. You have a bunch of operations that you might run, and you actually don’t want it to run. You want it to do all of these things right now, because maybe you want to try to optimize your startup. Let’s get this engine working, let’s get that engine working, there’s no reason why we have serialize them.

combineFutures is a nice little type-safe function that will take any of your two Futures and will create a new Future whose result is a two pole. Maybe I have some model that generates a shift model object or a vehicle model object, and now I’m going to combine them into a single Futures. When both of those things are successful, return to me the result. And again, if one of these Futures fails, everything fails.


public protocol CompletionType {
	associatedtype T
	var completion : Completion<T> { get }
}

I’ll touch on a few more things that FutureKit will do. This is where we get into a little bit of the advanced stuff but basically there’s this thing called the CompletionType protocol. This is an extension of FutureKit that will let you take anything else you have in, if it’s already asynchronous.

Maybe you want to treat an Alamofire request as a Future, you can extend your own stuff and turn them into things that FutureKit will automatically interpret and it can complete a Future. So it can be added into Future handlers, which is very nice.


public protocol ErrorTypeMightBeCancellation : ErrorType {
		var isCancellation : Bool { get }
}

There is this issue that I talked about where cancellations are not errors. If you have libraries that already generate errors that are cancellations, and you want to turn them into cancellations, you can extend your error with this handy ErrorTypeMightBeCancellation. Then you compute the isCancellation. If this error is thrown in anyone of those handlers, FutureKit will automatically just convert that to cancelled.

Advanced Stuff/Conclusion (36:11)

Once you understand the basics, we can start to talk about the advanced stuff. I won’t get into all the details of these libraries, but I want to give a quick overview.


NSCache.findOrFetch(key, expireTime:NSDate? = nil,
onFetch: () -> Future<T>)

Caching Futures is a thing I tend to do a lot. And the idea is that, when you have an expensive operation, that has to be done in the async, when you’re done with that operation, you stick it in a cache so you don’t have to do it again. This could be an image cache or any other kind of expensive operation cache.

But caches sort of have the opposite issue, because you start this big asynchronous operation, and only when it’s done do you stick it in the cache. As you write your code and as your using some kind of Futures or asynchronous background, and you realize that you might have three different places in your code that all want the same thing, and they’re all asking for it before the first one is done caching.

There’s a nice little trick where there’s already an existing extension that runs NSCache. This is called findOrFetch, which will let you define some kind of key, and if it fails then you return a method that returns a Future and it will go and fetch it. Then if the second or the third or the fourth request hits the cache, they all get the same Future. They’re all waiting on the same result, so you can accelerate it.

There’s this object called the FutureBatch. This is for when combineFutures is not good enough, particularly if you have an unknowable array of Futures and you don’t know how many there are going to be. You also have a lot more control over deciding if one of the subFutures fails, does the whole batch fail or does it not? If you need to get the independent result of every one of your subFutures, you can use the FutureBatch.

There’s also the FutureFIFO, and this turns out to be so simple, but so powerful.


let fifo: FutureFIFO()
let f:Future<UIImage> =
	fifo.add {
		return functionThatBuildsUImage()
}


One of the other things that happens when you’re writing a lot of asynchronous code is that you realize you will have to serialize things. The FutureFIFO is first in, first out. It gives you an add method, and you just return a Future again. It’ll make sure that these blocks that execute won’t execute until the previous block has completed its Future.

This is not like in a separation queue, where it’ll make sure that that block of code will execute. This is a logical asynchronous queue. One of the best examples I can give you is the classic call:

I have to call the server. I have some kind of REST operation, and I want to make sure that I’m going to make an API call and then I’m going to get the JSON, and then I’m going to modify the database, and then I’m going to write to the database, and then I come back with the result, and I actually don’t want to do the next API call. I want to be able to have the data in the database done.

But those are all different asynchronous queues, that all have to get done. Here you shove it in a FIFO and the next model operation won’t start until the previous one is done.


NSOperationQueue.add<T>(block: () throws -> (Future<T>)) ->
Future<T>

let opQueue: NSOperationQueue
let f:Future<UIImage> =
	opQueue.add {
		return functionThatBuildsUImage()
}

NSOperations are terrible to write, but they’re actually really easy if you’re using something like a Futures implementation.

Let’s say I wanted to, instead of using a FIFO, control the level of parallelism. I want a batch where I have an image operation, and I know I have three cores in my iPad, and I want to run two simultaneous image operations. I might use an NSOperationQueue, define the concurrency level to two, and then I can add these methods that will execute these blocks that will execute inside the NSOperationQueue.

We started using Futures to kill all those evil delegates. If anybody’s ever had to look at delegate code, delegates are one of those horrible things in asynchronous that just adds, that turn your iOS or Mac OS code into spaghetti, because it distributes the logic around.

Sometimes people will invoke a view controller, and when the view controller is done, then there’s some kind of delegate that gets called back to tell you the result. One of the things that we do is we just add a property to that view controller saying, if you want to know whenever the user has selected the thing or whatever he wants, you create a Future. If that thing has a lot of different outputs then we create an enumerated value. The user picked this and that becomes the Future result.


public extension SignalProducerType {

public func mapFuture<U>(transform: Value ->
Future<U>?) -> SignalProducer<U?, Error>
}

I do get a lot of questions about the difference between Futures and Reactive. Futures and Reactive will play well together if you understand when to use one and when to use the other.

I have found a lot of people have been using Reactive code to do things that should have been done in a Future, because they know how to do it in Reactive. If I have a signal that will be changing over time and I want to monitor it, you want to use any one of these Reactive stacks, like ARC Swift or ReactiveCocoa.

If you’re just going into the background and doing something and returning a single result, and closing your signal, if you have any Reactive code that does that, you should probably be using a Future, because what you’re missing in the FutureKit is all of that wonderful composability.

If you ever try to compose asynchronous operations in any of these asynchronous libraries, it can be very, very difficult. When you’re just trying to fetch and retrieve, and doing something in the background, and you’re going to come back with one result and you’re done, that’s a Future.

Q & A (40:58)

Q: What about dynamically composing futures? So let’s say that you need to do some kind of polling operation towards the server, and you don’t know how many polls you will need until you actually get there, but in the end to the API consumer, you just want to present the single Future is that possible?

Michael: You basically use a Promise. Instead of trying to compose with the onComplete and onSuccess, we did have a method that said go to the server and try to get this result, and then come back and then if that failed, instead of wrapping it, we had this single Promise object that we find, that we would go, oh, how many times have I tried? Haven’t tried again, let me sleep and then try again. So it turns out that actually isn’t hard, but you are right, it wasn’t intuitive.

Q: I do a lot of Reactive in the app that I work on, like ARC Swift. I was wondering if you could expand a little on some of the patterns you might do with Futures and Promises versus Reactive and RX.

Michael: One of the typical things you might have is a series of operations coming in, and you want to insert an asynchronous operation. It turns out it’s easy to build actions with Futures, versus ReactiveCocoa. At the same time, there are things that you can do in Reactive that you can’t do with Futures. I generally tell people the advantage of Futures is all about that level of composability. It’s all about being able to go, map it to a value or to some subFuture. That’s the strength.

Resources

About the content

This talk was delivered live in June 2016 at AltConf. The video was recorded, produced, and transcribed by Realm, and is published here with the permission of the conference organizers.

Michael Gray

Tech Lead, R&D, Ambulnz.com. Author of Futurekit.org. Spent a long time working on code at great places like Squarespace, Flyby Media, Meetup.com, Blackberry, and Intel. Mostly harmless.

4 design patterns for a RESTless mobile integration »

close