Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

2.7 Closures

Within the Swift language we are introduced to the concept of closures. Closures are similar to blocks in the Objective-C world and lambdas in other languages. Any way you look at it, they are extremely important to understand, as they are going to show up quite often in out-of-the-box functions provided by Apple.

Related Links

2.7 Closures

In the previous lesson, we learned about functions and ultimately, function types. And that's a very good segue into a rather interesting topic in the Swift programming language known as closures. But before we get that far, let's talk a little bit about what a closure is, revisit the concept of a function type, and then get into the usage of these closures. So a closure is really just a function or a group of related functionality that's put together that you can pass around as a parameter inputs and outputs. So that's basically a function, or at least a definition of function that we talked about before. But the difference is that the Swift closure kind of more similarly mirrors a, an Objective-C block, if you're familiar with that. Or in other languages, maybe something like a lambda, or a lambda expression. So it's really kind of a, a way to encapsulate functionality, kind of, almost like anonymously, and then pass that information around. So let's revisit the concept of function types that we talked about in the previous lesson. So, if you recall, a function type is really nothing more than using the signature of a function, which would be the inputs and the outputs. And assigning that as a type to a particular variable, or something along those lines. So, let's see what that might look like. So let's say that we were to create a particular variable, so we'll say var myfunc, and we're gonna specify that the type of this is actually going to maybe take in a couple of string parameters. And have an output here of a string parameter, something along those lines. Now, this is going to create, or declare, that myfunc is actually going to represent a function that takes two string inputs, and has a string output. So then, later on in our code, we can re, reference myfunc and we can pass it certain data. So what we can do is we can start to create a series of functions that match this particular signature and pa, and assign those to this myfunction variable. And so we could do that in this mechanism, or we could that by passing that particular function type or functions that match that signature into other methods or get them out of other methods. So that's kind of the basic concept behind the function type. Now, we introduce this idea of a closure now, so let's see what this looks like if we were to follow the same basic premise. So, within the Swift standard library, which we're going to talk about in more detail later on, there are a number of predefined, say, global methods that we have access to. While we are using the Swift language that are just kinda little helper methods, things that help you print things out to the screen as well as do some basic algorithms. So one of the things that exists within the standard library is this concept of sorted. Now what the sorted method does, as you can see, there are two versions of it. One of them takes in just a source, which happens to be an array, which we'll also talk about a little later. And the second part takes in an array as well as this idea of isOrderedBefore it as you can see here. This looks to be like a function type. So I see that i take in two elements and then I return a Boolean. So let's see how we can use this with a function type that we talked about before and then transition over, and using a closure. So as you can see here, i need to be able to take two elements, so this is if I'm going to compare two elements. So the basic premise here is that's it's going to go through the entire array, it's going to take two elements of that array and compare them together to see which one is before the other one. So we need to provide that sort of functionality. So let's go ahead and create an array. So we'll just say that we have a variable and we'll call it names. And this is going to be initialized to an array and an array is denoted by these square brackets and we'll say Derek, John, Amanda, and Bart. So there is our array. We've initialized it to those four names, and now we wanna be able to sort this array. So one way that we could do this, and we can sort this any way we want. It doesn't have to be alphabetical. We could provide any sort of implementation. To actually sort this, but we're gonna try to do this alphabetically just to kinda get things started. So what we're gonna do is we're going to create a function that matches this particular function type, so we take in two elements and we return a Boolean. So that's not too hard, so we'll say that here's a function, and we're just gonna call this alphabetical. And we're going to say that, we, we're gonna have two inputs. We're gonna have s1, and that's gonna be a string. And we'll have s2, which'll be the second element, and that's also going to be a string. And then ultimately, this is going to return a Boolean, just like that. So now we're gonna give it the function body, or the implementation, and this is gonna be fairly simple. We're just gonna say that we want s1 to be less than s2. Now this is going to do some string comparison to see if the value of the particular string of s1 is less than s2, then it's going to succeed and then ultimately put that s1 before s2. So now we're going to call this sorted method. And this is actually going to return a value for us, so we'll say var sortedArray is going to be equal to, and now we're going to pass in our source. And our source is going to be names, and our function here, or our function type, is going to be alphabetical. And in this particular case, all we have to pass in is the particular name of this function, and I do have to return this value. All we have to do is pass in the name of this function, and it's going to know that that particular function, it's going to check to make sure that its function type or signature matches what this method needs. So as you can see here, it successfully executed. It executed six times and now we have Amanda, Bart, Derek, and John. So they have been alphabetized based on what we've done here. Now if we wanna reverse these, if we wanted to go in reversed alphabetical order, we could copy this and we'll create a new function. We'll paste that here and we'll call this, reverse. And in this case, we'll make sure that s1 is actually greater than s2 like that. So no we can change this to be reverse, like this, and now we get it in reverse alphabetical order. John, Derek, Bart, and Amanda. So as you can see, this is one of the useful ways to, or one of the most popular ways to use this concept of function types. But, this can become a little cumbersome because now we definitely have to create these functions. We have to maintain them, and then we, ultimately, have to pass them into these types of methods or to these functions. Well, that's where closures come into play, where it gives us a little bit more flexibility to say, I don't really want to manage this. I'm only going to use this functionality, maybe, in one place. So, just go ahead and execute it. I don't have to worry about, I don't want to have to worry about creating these functions and all this kind of stuff. I just want to be able to, to find some functionality in place, like a block or a lambda expression. So, the way that we do that is through the concept of a closure. Now, a closure has a specific syntax. It is, starts and ends with the curly braces. So it's gonna start end end with these curly braces, and then we're going to specify the input parameters, if there are any. So, in this case, we'll do a similar concept here. Let's say we have two strings as the input parameters. And then of course we specify the return type, just like we did before. That's a Boolean. And then we specify a key word in which is going to say that this particular function type is going to be contained within the next statements. And those next statements are what's going to define the actual body of this closure. So everything I do after the in is going to be the body of this particular closure. So in our case I can do something similarly to what I did up here, and I could say return s1 less than s2, so this would be very similar. This is a closure that's going to represent this concept of alphabetical. And the cool thing about closures is that if you're using methods that require you to pass in something that matches the function type of say, two strings in as parameters and a Boolean out. Just like we did here. I can replace this reference to a function with a closure because they're interchangeable. So, let's go ahead and see what that would look like. So, now, I could get rid of all of this. So, let's rewrite this example like we did before, without having to worry about these methods up here. So, we'll say, var sortedArray is going to be equal to, sorted, and we're going to pass in names. And then we're going to come in and we're going to say, these are our curly braces to denote a closure. Then we have two inputs and we're gonna provide names for these inputs so we can reference them within the body of our closure. So we'll say we have an s1, which is a sting, an then we have an s2, which is a string. And then we're going to use our closure to return a Boolean because that's what this particular method is, or function is expecting. And then we'll say in, and then within here, we'll just use the same implementation as we did up here. We're going to return s1 less than s2. Paste there. And as you can see now, we have executed. And we see that now our resulting sortedArray value here is Amanda, Bart, Derek, John. So we did actually execute six times without having to pre-create any sort of functions like we did up here. We did it all in line, similarly to how we do with blocks or lambda expressions. So, that's the basic concept here behind a closure. So, we can do all this stuff in line. Now there's a couple of little tweaks we can go through here. Now, if we are specifying that a closure is going to be in place of a function type. So in our case, when we're calling our sorted method. You can see here that it's expecting two types here that are going to return a Boolean so we can, kind of, cheat a little bit and use some type inference to reduce what this looks like a little bit. So it knows that this method needs to take in two elements and return a Boolean. So instead of duplicating that work here, we can actually stop providing all of this and we can merely say that we have, we're gonna have an s1. And we're gonna have an s2, and that's going to be in, using our in keyword to pr, to then denote the body is coming and then we're returning s1 and s2. So now this only works if we are in a scenario where the actual function type is defined and known to be something. And in this case, because we're calling this sorted method, then this is going to work. But if we're just creating these in kind of random spots, where the types aren't known, or maybe where the function type isn't known. You're going to have to do that explicitly. So this is just a bit of a short hand notation that's going to let us define this particular closure. So that's the basic concept behind closures. There's some other information about them and, and being able to tweak these several different ways, and I'll leave that extra research up to you. But the closure is a very cool idea, and you're going to find many, many uses for it throughout your Swift programming. Really, anywhere you would find use for blocks, say, in Objective-C, so it's definitely a nice little thing to have in your bag of tricks.

Back to the top