0 1 00:00:00,600 --> 00:00:01,150 Hey, guys. 1 2 00:00:01,170 --> 00:00:04,790 Welcome to another Swift Deep Dive. In this Deep Dive, 2 3 00:00:04,800 --> 00:00:07,020 we're going to talk about Closures. 3 4 00:00:07,020 --> 00:00:13,440 Closures are essentially anonymous functions or functions without a name and they're essentially a self-contained 4 5 00:00:13,440 --> 00:00:17,420 package of functionality that we can pass around and use. 5 6 00:00:17,430 --> 00:00:22,320 So we've seen a lot of functions up till now. And we know that when we create a function, we always start 6 7 00:00:22,440 --> 00:00:24,240 with the func keyword. 7 8 00:00:24,240 --> 00:00:30,180 And then we give our function a name, and then we have a section that's enclosed in parentheses that 8 9 00:00:30,180 --> 00:00:34,710 represent the input parameters and the input parameter type. 9 10 00:00:34,740 --> 00:00:41,160 And finally, we have this little dash and angle bracket to represent the returnType, i.e., what is the 10 11 00:00:41,160 --> 00:00:45,440 data type of the thing that we will output from our function. 11 12 00:00:45,630 --> 00:00:52,110 And in the body of our function, i.e., between the curly braces, we get our function to do something, and 12 13 00:00:52,110 --> 00:00:59,100 then finally, if our function has an output, then we get it to return the output. 13 14 00:00:59,100 --> 00:01:02,540 So, essentially, our function is a little bit like a bread cutting machine. 14 15 00:01:02,610 --> 00:01:08,520 You have an input, say, your bread, and then you pass it through your function and you get an output. 15 16 00:01:08,520 --> 00:01:11,610 Something happens to the bread, it gets cut up in slices. 16 17 00:01:11,610 --> 00:01:17,550 You can determine how thick or thin the slice is. But, essentially, all it is is a bunch of functionality 17 18 00:01:17,820 --> 00:01:23,940 that's packaged together and given a function name so that we can refer to it later on when we need 18 19 00:01:23,940 --> 00:01:31,530 that functionality, so we can call the method or call the function by its name, giving it inputs and receiving 19 20 00:01:31,530 --> 00:01:32,840 the outputs. 20 21 00:01:32,880 --> 00:01:37,320 So up till now, we've seen three variations on function. 21 22 00:01:37,320 --> 00:01:43,850 We've seen functions that only do something without needing an input or having an output. 22 23 00:01:43,950 --> 00:01:49,950 And then we've seen functions which take an input and then we've seen functions which do all three, i.e., 23 24 00:01:49,970 --> 00:01:54,650 a function that takes input and has an output and does something in between. 24 25 00:01:55,050 --> 00:01:58,110 But let's now look at the step beyond that. 25 26 00:01:58,140 --> 00:02:06,360 The interesting thing about functions is that you can actually pass a function as an input to another 26 27 00:02:06,360 --> 00:02:13,170 function and you can also have a function as the output of another function. 27 28 00:02:13,440 --> 00:02:16,110 So I can show you this better in playgrounds. 28 29 00:02:16,110 --> 00:02:18,900 So I've got a blank playground here. 29 30 00:02:18,900 --> 00:02:24,630 What I'm going to do is I'm going to create a function that's called calculator, and what it does is 30 31 00:02:24,750 --> 00:02:33,570 it takes a number n1, and it also takes another number n2, and they're both integers, and the calculator 31 32 00:02:33,690 --> 00:02:36,080 also returns an integer. 32 33 00:02:36,150 --> 00:02:44,580 So all that our calculator is going to do right now is it's just going to add n1 to n2, and it returns 33 34 00:02:44,610 --> 00:02:48,690 the result of the first number added to the second number. 34 35 00:02:48,960 --> 00:02:57,420 So let's give it a spin. Let's say a calculator and give it to numbers 2 and 3. And we can see the output 35 36 00:02:57,600 --> 00:02:58,980 is 5. 36 37 00:02:58,980 --> 00:03:02,150 So all is working as expected. 37 38 00:03:02,160 --> 00:03:10,110 Now, say, if we wanted to change the calculator to a multiplication calculator, then we would have to go 38 39 00:03:10,110 --> 00:03:14,040 into the body of the calculator and change the return statement. 39 40 00:03:14,040 --> 00:03:23,760 Now, what if we wanted to be able to pass in a function as an input to our calculator function in order 40 41 00:03:23,760 --> 00:03:28,050 to determine what sort of mathematical operation it should perform? 41 42 00:03:28,050 --> 00:03:33,780 So in order to do this, we're going to create another function, and I'm going to call my function add, 42 43 00:03:34,350 --> 00:03:36,390 and it, again, takes two numbers. 43 44 00:03:36,420 --> 00:03:41,320 So let's call it no1 and no2, 44 45 00:03:41,370 --> 00:03:45,990 and it returns a number as well. 45 46 00:03:45,990 --> 00:03:54,380 So now we're going to return no1 + no2. 46 47 00:03:54,380 --> 00:04:01,490 So this is our basic addition operand, essentially, and we're going to go and modify our calculator 47 48 00:04:01,520 --> 00:04:08,900 so that it not only takes two numbers as inputs, but we're gonna give it a third input in the form of 48 49 00:04:08,930 --> 00:04:15,980 a function. In order to put this function in as an input, we're going to have to boil down this function 49 50 00:04:16,070 --> 00:04:17,680 into its data types. 50 51 00:04:17,810 --> 00:04:24,320 So if we have a look at this function, you can see that it takes two inputs, both in the form of integers 51 52 00:04:24,500 --> 00:04:27,410 and returns an integer as an output. 52 53 00:04:27,440 --> 00:04:37,230 So if you boil down this function to its data types, essentially, all it is is int, int, and returns an int. 53 54 00:04:37,250 --> 00:04:47,180 So if we take this representation of that function and we pass it in as the data type of our third parameter 54 55 00:04:47,240 --> 00:04:50,510 which we'll call operation, 55 56 00:04:50,510 --> 00:04:57,170 so as you can see, we've got three parameters as inputs for our calculator function, n1, n2, so those 56 57 00:04:57,170 --> 00:05:00,090 are the two numbers that we're going to give our calculator. 57 58 00:05:00,200 --> 00:05:08,990 And then, finally, we've got a parameter called operation and the data type of operation is in the format 58 59 00:05:09,140 --> 00:05:16,130 of a function, i.e., it's not just int, it's not just string, but it's actually the boiled down version 59 60 00:05:16,220 --> 00:05:23,080 of a function, i.e., two integer parameter inputs and returns a single integer. 60 61 00:05:23,090 --> 00:05:29,210 Now, the next thing to do is to change this return statement. At the moment, our calculator is still returning 61 62 00:05:29,510 --> 00:05:31,940 the first number multiplied it by the second number. 62 63 00:05:31,940 --> 00:05:40,160 But instead, what we want to do is we want to call this function that's currently called operation, 63 64 00:05:40,250 --> 00:05:45,770 so we can, instead, return operation and we can give it the required inputs. 64 65 00:05:45,770 --> 00:05:52,470 So as we specified, it takes two inputs and returns one output, and the two inputs have to be integers. 65 66 00:05:52,520 --> 00:05:57,730 So this is where we're going to pass in our n1 and n2. 66 67 00:05:57,900 --> 00:06:04,700 So now, Xcode is complaining over here because this is no longer how you call the calculator function 67 68 00:06:05,060 --> 00:06:08,550 because instead of having two parameters, it's now got three. 68 69 00:06:08,630 --> 00:06:13,830 So let's try calling it again and get Xcode to type out the function for us. 69 70 00:06:13,850 --> 00:06:22,400 So the first number is, again, two, second number is three, and the operation is going to be "add," so that we 70 71 00:06:22,400 --> 00:06:27,680 pass in this function as an input parameter. 71 72 00:06:27,680 --> 00:06:34,080 And, essentially, what happens is that two goes over here, three goes into here, 72 73 00:06:34,160 --> 00:06:41,300 and the operation, this function add gets passed in over here as the operation. 73 74 00:06:41,300 --> 00:06:49,640 And what we return from our calculator function is we return by calling this function that's under the 74 75 00:06:49,640 --> 00:06:55,370 operation parameter passing in the original inputs n1, n2. 75 76 00:06:55,490 --> 00:07:02,200 So whichever function gets passed in as the operation will process these two numbers. 76 77 00:07:02,210 --> 00:07:11,540 So in this case, we passed in the add a function as the operation, and the n1, n2 then goes over 77 78 00:07:11,540 --> 00:07:15,820 here as the inputs, and we return n2 + n2. 78 79 00:07:15,860 --> 00:07:23,350 So if I create another function, say, let's call it multiply, then I can have again two inputs. 79 80 00:07:23,360 --> 00:07:25,030 So no1, 80 81 00:07:25,040 --> 00:07:26,340 no2. 81 82 00:07:27,260 --> 00:07:31,110 And it also returns an integer. 82 83 00:07:31,220 --> 00:07:37,010 So in this case, we're returning no1 multiplied by no2. 83 84 00:07:37,010 --> 00:07:45,320 So if I go ahead and change the function that we pass in to our calculator by changing it to multiply 84 85 00:07:45,320 --> 00:07:53,030 instead, then you can see that the result changes to 6, because now instead of this add function being 85 86 00:07:53,030 --> 00:07:58,980 passed in as the operation, we've actually got the multiply function being passed in here. 86 87 00:07:59,390 --> 00:08:07,220 So I hope you'll believe me now when I tell you that you can pass in functions as inputs into other 87 88 00:08:07,220 --> 00:08:12,980 functions and you can also use functions as the return type. 88 89 00:08:12,980 --> 00:08:17,870 So now let's clean this up a little bit because we've actually got quite a few lines of code to do something 89 90 00:08:17,870 --> 00:08:19,150 quite simple. 90 91 00:08:19,310 --> 00:08:26,270 So to make things clear, I've got a multiply function that gets passed into the calculator as an input 91 92 00:08:26,690 --> 00:08:30,890 and it's used to perform the calculation. 92 93 00:08:30,890 --> 00:08:35,800 So at the moment, everything's very wordy and we've got quite a few lines of code. 93 94 00:08:35,840 --> 00:08:41,270 Now, if I wanted to cut this down, I can instead use a closure. 94 95 00:08:41,390 --> 00:08:48,500 So closures if you remember are anonymous functions or you can consider functions as named closures. 95 96 00:08:48,770 --> 00:08:54,110 But, essentially, they're just packages of functionality which you can pass around freely. 96 97 00:08:54,180 --> 00:08:59,580 So if we have a look at the structure of our function, which we're very familiar with, we've got a section 97 98 00:08:59,610 --> 00:09:00,870 that's the input. 98 99 00:09:00,870 --> 00:09:03,590 Remember, that's the part between the parentheses, 99 100 00:09:03,840 --> 00:09:05,630 and then we've got a part that's the output. 100 101 00:09:05,640 --> 00:09:09,090 So that's the part that comes after the dash and angle bracket. 101 102 00:09:09,360 --> 00:09:15,260 And then we've got this func keyword which we've been using every single time we created a new function. 102 103 00:09:15,300 --> 00:09:19,400 And finally, we've got a part that represents the name of the function. 103 104 00:09:19,410 --> 00:09:26,460 So in order to convert this function to a closure, all we need to do is to remove the keyword func and 104 105 00:09:26,460 --> 00:09:28,100 the name of the function. 105 106 00:09:28,320 --> 00:09:36,120 And then we move this open bracket from the end of the line to the beginning of the closure and we replace 106 107 00:09:36,120 --> 00:09:39,620 it instead with the keyword "in." 107 108 00:09:39,630 --> 00:09:45,680 So now we've successfully converted a function into a closure. 108 109 00:09:45,810 --> 00:09:48,720 And as you can see, it's pretty anonymous. 109 110 00:09:48,780 --> 00:09:56,580 All you have is a block of code which you can pass around freely into other functions or set as a variable. 110 111 00:09:57,210 --> 00:10:04,370 So let's try and do the same with our multiply function. Instead of calling this multiply function, 111 112 00:10:04,380 --> 00:10:10,950 what we can do instead is we can pass in a closure. So remember the first thing we do is we delete the 112 113 00:10:10,950 --> 00:10:14,440 func keyword and the name of the function. 113 114 00:10:14,550 --> 00:10:21,810 The next thing we do is we move this open bracket to the beginning of the block of code and we replace 114 115 00:10:21,810 --> 00:10:23,930 it with the keyword "in." 115 116 00:10:24,690 --> 00:10:32,250 So now we have our closure and we can put it in here as an input parameter. 116 117 00:10:32,250 --> 00:10:39,450 So you'll notice that nothing has changed, output wise, it's still working as it did before, but we've 117 118 00:10:39,450 --> 00:10:46,410 now cut down on two lines of code. But it gets crazier than that. We can actually cut down this code even 118 119 00:10:46,410 --> 00:10:47,190 further. 119 120 00:10:47,220 --> 00:10:53,030 So as you know Swift has the ability to infer data types based on the value. 120 121 00:10:53,040 --> 00:11:00,660 So if you have a variable "a" that contains a number, then Swift will automatically assign the data type 121 122 00:11:00,990 --> 00:11:07,280 int to this variable, and that's called type inference. And we can use that here as well. 122 123 00:11:07,290 --> 00:11:12,520 So instead of explicitly declaring the data type of these parameters, we can actually delete it 123 124 00:11:12,660 --> 00:11:19,680 and it still works fine. Because when we pass in these inputs into this closure, the compiler will be 124 125 00:11:19,680 --> 00:11:23,820 able to figure out what the data type of these parameters should be. 125 126 00:11:23,940 --> 00:11:27,390 And you can do the same thing with the return type. 126 127 00:11:27,390 --> 00:11:33,150 So you can actually get rid of this part entirely because we have a calculation in here, i.e., the first 127 128 00:11:33,150 --> 00:11:38,630 number multiplied by the second number, the output has a data type based on the inputs. 128 129 00:11:38,820 --> 00:11:46,850 So we can actually get rid of this part, too, and get the compiler to infer the data type of the output. 129 130 00:11:46,860 --> 00:11:52,840 Now, our code is beginning to look a lot shorter than it did before. And I'm not even done yet. 130 131 00:11:52,860 --> 00:11:59,940 We can also get rid of this return keyword because we're inside a closure and there is a operation that's 131 132 00:11:59,940 --> 00:12:01,020 being carried out. 132 133 00:12:01,080 --> 00:12:07,680 The compiler can infer that you want something to be returned based on the simple fact that you're processing 133 134 00:12:07,680 --> 00:12:10,980 something inside your closure. 134 135 00:12:10,980 --> 00:12:14,880 So we're pretty much at the point where everything can be expressed in one line. 135 136 00:12:14,880 --> 00:12:21,420 Now, you might think that it can't get any shorter, but it can. Because in Swift, closures has the ability 136 137 00:12:21,420 --> 00:12:25,130 to provide anonymous parameter names. 137 138 00:12:25,140 --> 00:12:30,180 So here we've given our parameters names: no1 and no2. 138 139 00:12:30,240 --> 00:12:34,700 And later, we refer to those parameter names to carry out our expression. 139 140 00:12:34,800 --> 00:12:40,230 But instead of doing this, you can actually use the anonymous parameter names. 140 141 00:12:40,320 --> 00:12:49,920 So in Swift, a dollar sign with a zero refers to the first parameter, and a dollar sign with a 1 refers 141 142 00:12:49,920 --> 00:12:52,770 to the second parameter, and so on and so forth. 142 143 00:12:52,800 --> 00:13:02,280 So instead of expressing this line like so, we can actually just change it to first parameter multiplied 143 144 00:13:02,400 --> 00:13:04,750 by second parameter. 144 145 00:13:05,190 --> 00:13:14,430 So now if I assign the result of this calculator function to a constant and then I print out this result, 145 146 00:13:14,850 --> 00:13:21,450 you can see that we've still got the same result as before even though we've cut down four lines of 146 147 00:13:21,450 --> 00:13:24,840 code, everything is still working exactly the same. 147 148 00:13:24,840 --> 00:13:31,110 And to take this to the extreme, we can actually cut down this line even further, believe it or not, because 148 149 00:13:31,110 --> 00:13:39,630 in Swift there is a rule whereby if the last parameter in your function is a closure, i.e., everything 149 150 00:13:39,630 --> 00:13:42,890 between the open and closing curly braces. 150 151 00:13:42,900 --> 00:13:49,950 That's what our closure has simplified down to. Then you can actually omit the last parameter name and 151 152 00:13:49,950 --> 00:13:56,010 you can close the input section, and simply just have the closure trailing at the end. 152 153 00:13:56,010 --> 00:13:58,750 So this is called a trailing closure. 153 154 00:13:58,830 --> 00:14:03,420 So, again, as you can see, that has done nothing to change our result. 154 155 00:14:03,420 --> 00:14:06,260 Everything is still working as it did before. 155 156 00:14:06,540 --> 00:14:12,700 But instead of all of this, we now just have a single line. 156 157 00:14:12,780 --> 00:14:19,170 So one of the nice things about closures is that they can dramatically simplify your code and cut down 157 158 00:14:19,170 --> 00:14:20,200 on your code. 158 159 00:14:20,310 --> 00:14:27,180 But the downside to that is that readability suffers, because for somebody who is not very familiar with 159 160 00:14:27,180 --> 00:14:34,380 Swift coming in and looking at this line of code, it can be quite confusing. Because as you remember, we 160 161 00:14:34,380 --> 00:14:42,180 went through many many steps in order to cut down all of this expressive syntax into something that 161 162 00:14:42,180 --> 00:14:43,850 is very, very succinct. 162 163 00:14:43,860 --> 00:14:50,340 Now, you can argue that shorter is better, or some programmers might argue that this has way more style 163 164 00:14:50,700 --> 00:14:57,240 then something like this, which is true, but you always have to strike the balance between simplicity 164 165 00:14:57,390 --> 00:14:58,770 and readability. 165 166 00:14:58,770 --> 00:15:03,720 So that decision is mostly up to you. If you become more and more familiar with the language, you might 166 167 00:15:03,780 --> 00:15:09,070 actually have a preference of having a vastly simplified code file. 167 168 00:15:09,090 --> 00:15:15,780 Now, of course, this is just a made-up example to show you the process of passing in functions as inputs 168 169 00:15:15,840 --> 00:15:18,540 or passing in functions as outputs. 169 170 00:15:18,540 --> 00:15:24,810 This code doesn't stand up in real life because it's so much easier to simply just write "n1 * n2 170 171 00:15:24,900 --> 00:15:26,860 equals the result," 171 172 00:15:26,910 --> 00:15:27,600 right? 172 173 00:15:27,630 --> 00:15:31,050 So let me show you how we would use this in real life. 173 174 00:15:31,050 --> 00:15:36,990 Now, say, if we have an array with a bunch of numbers and we want to be able to add 1 to each of the 174 175 00:15:36,990 --> 00:15:38,570 items in the array. 175 176 00:15:38,610 --> 00:15:44,070 Now, the roundabout way of doing this is using what's called a for-loop and you can iterate through each 176 177 00:15:44,070 --> 00:15:47,410 of these items in order to add 1 to every one of them. 177 178 00:15:47,460 --> 00:15:53,690 But there's a much simpler way of doing this because there is a function called map that Swift provides 178 179 00:15:53,700 --> 00:15:58,410 that allows you to transform every single item in a collection type. 179 180 00:15:58,410 --> 00:16:04,190 So collection types are arrays or dictionaries, basically, collections of items. 180 181 00:16:04,200 --> 00:16:06,050 So let me show you how it would work. 181 182 00:16:06,060 --> 00:16:09,740 We first have to define a rule in order to transform our array. 182 183 00:16:09,780 --> 00:16:19,020 So if I create a function code addOne and all it does is it takes one number and it returns a number, 183 184 00:16:19,050 --> 00:16:21,210 but, of course, with 1 added to it. 184 185 00:16:21,300 --> 00:16:25,910 So, essentially, we return n1 + 1. 185 186 00:16:25,950 --> 00:16:27,500 So that's pretty simple, right? 186 187 00:16:27,750 --> 00:16:34,830 But then what we can do is we can tap into our array and we can use the map function to transform this 187 188 00:16:34,830 --> 00:16:35,740 array. 188 189 00:16:35,790 --> 00:16:41,310 Now, the map function takes an input in the form of another function. 189 190 00:16:41,340 --> 00:16:49,380 So if we use addOne here and you go ahead and hit enter, you can see that your array gets transformed 190 191 00:16:49,740 --> 00:16:54,290 with every single item being one greater than previously. 191 192 00:16:54,300 --> 00:16:55,770 So that's pretty neat. 192 193 00:16:55,770 --> 00:17:03,150 But why do we have to write so much code when we know all about closures? And I'd like to pose this as 193 194 00:17:03,150 --> 00:17:03,790 a challenge to you. 194 195 00:17:03,800 --> 00:17:10,560 Can you write the code to turn this into a closure instead? Pause the video, check the closure syntax, 195 196 00:17:10,680 --> 00:17:14,840 and I'll show you the solution in a bit. Ready? 196 197 00:17:14,840 --> 00:17:16,460 Here's the solution. 197 198 00:17:16,610 --> 00:17:21,890 So if you remember, in order to turn this into a closure, we delete the func keyword and would delete 198 199 00:17:21,920 --> 00:17:24,000 the name of the function. 199 200 00:17:24,110 --> 00:17:32,600 Then we move the open curly brace to the beginning of the code block and we replace that instead with 200 201 00:17:32,600 --> 00:17:34,400 the keyword "in." 201 202 00:17:34,430 --> 00:17:39,700 So now we can put this, instead of using that function name. 202 203 00:17:39,860 --> 00:17:44,660 And, of course, we can use some of those snazzy tricks that we learned about previously where we first 203 204 00:17:44,660 --> 00:17:52,130 used type inference to make the compiler infer the data type of the input as well as the output. We can 204 205 00:17:52,130 --> 00:17:52,490 use 205 206 00:17:52,550 --> 00:18:00,470 an implicit return, because we only have one expression inside our closure, so we can get rid of the return 206 207 00:18:00,470 --> 00:18:01,610 keyword. 207 208 00:18:01,700 --> 00:18:10,220 And finally, we can get rid of this whole thing by just simply using the shorthand notation for the parameters 208 209 00:18:10,280 --> 00:18:16,430 and we say the first parameter plus 1. And we can go even further and get rid of these parentheses 209 210 00:18:16,730 --> 00:18:25,580 because our closure is the last item in the list of parameters, i.e,. it's trailing. And if we print the 210 211 00:18:25,610 --> 00:18:33,890 result of this out, you can see that we've mapped our previous array to increase each item by 1. So Swift 211 212 00:18:33,890 --> 00:18:39,440 has three of these really useful high-level functions called map, reduce, and filter. And you can do some 212 213 00:18:39,440 --> 00:18:41,250 really useful things with them. 213 214 00:18:41,300 --> 00:18:47,420 For example, you've realized that your array contains integers, right? But we actually want to convert each 214 215 00:18:47,420 --> 00:18:49,610 of them into strings. 215 216 00:18:49,610 --> 00:18:57,410 So what you can do instead is this. Let's say, we create a new constant code newArray and we set it to 216 217 00:18:57,410 --> 00:19:07,340 equal array.map, and we use the string interpolation method where we enclose the integer inside 217 218 00:19:07,400 --> 00:19:08,200 a string. 218 219 00:19:08,210 --> 00:19:17,360 So now if we print out this newArray, you can see that it's composed of entirely strings. So we've essentially 219 220 00:19:17,360 --> 00:19:27,050 stringified each item in this array by simply writing a very short bit of code and using the map functionality. 220 221 00:19:27,050 --> 00:19:33,530 So in essence, you'll find that closures can be a very succinct way of expressing your code. And in the 221 222 00:19:33,530 --> 00:19:40,670 cases where you're passing in functions into other functions, it can make your code a lot more readable. 222 223 00:19:40,670 --> 00:19:46,640 Now, of course, that depends on your own familiarity with the syntax and other people's familiarity 223 224 00:19:46,640 --> 00:19:53,120 if you're working on a project together. But all in all, closures allow you to package anonymous blocks 224 225 00:19:53,240 --> 00:19:57,410 of functionality and pass it around in your code. 225 226 00:19:57,500 --> 00:20:00,950 So essentially, this is the syntax for a closure. 226 227 00:20:01,100 --> 00:20:05,410 You have the parentheses that surround the input parameters. 227 228 00:20:05,600 --> 00:20:12,560 You have the dash and angle brackets that specify the return type, and the "in" keyword denotes the beginning 228 229 00:20:12,740 --> 00:20:14,120 of your closure body. 229 230 00:20:14,210 --> 00:20:20,780 So this is the functionality that your closure is going to perform and everything is contained inside 230 231 00:20:20,840 --> 00:20:27,500 these curly braces. And the closure doesn't have a name or a funky word and you can recognize it by this 231 232 00:20:27,620 --> 00:20:35,030 syntax. If you'd like to know more about closures or review what we've discussed in this lesson, I recommend 232 233 00:20:35,030 --> 00:20:39,080 having a quick look at this section in the Swift Language Guide. 233 234 00:20:39,110 --> 00:20:43,760 As always, you'll find the link on the course resources page, and I'll see you on the next lesson.