📜 ⬆️ ⬇️

Anonymous Functions in Swift

This publication is an outline of the relevant section of the remarkable book “iOS 8 Programming Fundamentals with Swift” by Matt Neuburg, O'Reilly, 2015. An article describing the use of anonymous functions may be interesting for beginners or useful as a cheat sheet for more advanced developers.

Consider an example:

func whatToAnimate() {//self.myButton     Self.myButton.frame.origin.y += 20 } func whatToDoLater(finished:Bool) { printLn(“finished: \(finished)”) } UIView.animateWithDuration( 0.4, animations: whatToAnimate, completion: whatToDoLater) 

There is some oddity in this section of code. I declare whatToAnimate and whatToDoLater functions only to transfer these functions to the next line of code. And indeed, the names of these functions are no longer needed for anything — neither the names nor the functions will ever be reused again. It would be good to transfer only the bodies of these functions, without the need to declare their names.
')
Such functions are called anonymous, they have the right to exist and are often used in Swift.

Creating an anonymous function


To create an anonymous function, we do two things:
  1. Create a function body, including surrounding curly braces, but without a function declaration.
  2. If necessary, in the first line inside the curly brackets, after the in command, we describe the function argument list and the type of the returned variable.

Consider an example of how to convert a function to an anonymous one. Source Function Code:

  func whatToAnimate () { Self.mybutton.frame.origin.y += 20 } 

Here is an example of an anonymous function that performs the same task. We moved the list of arguments and the return type inside the curly braces:

  { () -> () in self.myButton.frame.origin.y += 20 } 

Now that we know how to create an anonymous function, let's see how we can use it. In our call to animateWithDuration, the point at which we call functions is the place where we pass the arguments to this function. So, we can create an anonymous function right at the same point, like this:

  UIView.animateWithDuration(0.4, animations: { () -> () in self.myButton.frame.origin.y += 20 } , completion: { (finished:Bool) -> () in printLn(“finished: \(finished)”) }) 

Anonymous functions are very often used in Swift, so you should make sure that we easily read and write such code. Anonymous functions are so common and so important that there are some abbreviations used in their creation. Consider such cases.

Omit the return type


If the compiler already knows what type of variable the function returns, then we can omit the arrow operator, the type and specification of the variable.

  UIView.animateWithDuration(0.4, animations: { () in self.myButton.frame.origin.y += 20 }, completion: { (finished:Bool) in printLn(“finished: \(finished)”) }) 


We omit the string with the in operator when there are no arguments in it.


If an anonymous function takes no arguments and if the type of the returned variable can be omitted, then the line with the in command can be omitted entirely:

  UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, ompletion: { (finished:Bool) in printLn(“finished: \(finished)”) }) 


Omitting argument types


If an anonymous function takes arguments, and their types are known to the compiler, then these types can be omitted:

  UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, completion: { (finished) in printLn(“finished: \(finished)”) }) 


Omit brackets


If argument types can be omitted, then parentheses around these arguments can be omitted:

  UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, completion: { finished in printLn(“finished: \(finished)”) }) 


We omit the line with in, even if it has arguments


If the return type can be omitted, and if the argument types are known to the compiler, you can omit the string with in and refer to the arguments directly from the body of the anonymous function using the names $ 0, $ 1, and so on in order:

  UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, completion: { printLn(“finished: \($0)”) }) 


Omit the argument names


If your anonymous function does not need arguments, then you can omit the arguments, replacing their names with an underscore in the line with in:

  UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, completion: { _ in printLn(“finished!”) }) 


Note. If your anonymous function accepts arguments, you must use them anyway. You can omit the string with in and use arguments for their names like $ 0, $ 1 and so on, or you can save the string with in and replace the arguments with an underscore, but you cannot omit the string with in at the same time and not use the arguments their names are $ 0, $ 1. If you do this, your code will not be compiled.

We omit the names of the arguments of the calling function.


If your anonymous function is the last parameter that is passed in the call, then you can close the call with a parenthesis to the last parameter, and then put the body of the anonymous function without specifying the names of the arguments. This method is called the trailing function.

  UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }) { _ in printLn(“finished!”) }) 


We omit the brackets of the calling function.


If you use a closing function and the function you are calling does not accept any other parameters besides the function you are passing, you can omit empty brackets in the call. For example, I will declare and call another function:

  func doThis(f: () -> ()) { f() } doThis { //    printLn(“Hello”) } 

This is the only situation in which you can omit the parentheses in the function call.

Omit the keyword return


If the body of an anonymous function consists of only one statement and this statement consists of a return value with the keyword return, then the keyword return may be omitted. In other words, in a situation where we expect the function to return a value, if the body of the anonymous function consists of only one statement, Swift implies that this statement is an expression whose value will be returned from the anonymous function:

  func sayHello() -> String { returnHello” } func performAndPrint(f: () -> String) { let s = f() printLn(s) } performAndPrint { sayHello() // return sayHello()   performAndPrint } 


Practical use


Consider an example. We have an array of variables and we need to get a new array consisting of the same values ​​multiplied by 2, called using the map method. The array method map takes a function that takes an argument and returns a variable of the same type as the array element. Our array consists of Int variables, therefore we will pass to the map method a function that takes an Int parameter and returns an Int. We could write an entire function, such as

  let arr = [2, 3, 4, 5, 6] func doubleMe(i:Int) -> { return i*2 } let arr2 = arr.map(doubleMe) 

However, this approach does not fully utilize Swift. We don't need the doubleMe function anywhere else, so it may well become anonymous. The type of variable it returns is known, so we don’t need to specify it. There is only one parameter, and we are going to use it, but we do not need a string with in if we refer to the parameter as $ 0. The body of our function consists of a single statement, and this is a return, so that we can omit return. And the map function does not accept any other parameters, so we can omit the parentheses and immediately after the anonymous function specify the name:

  let arr = [2, 3, 4, 5, 6] let arr2 = arr.map {$0*2} 

If you start using anonymous features, you will find that you often take advantage of the benefits they provide. In addition, you will often reduce the amount of code (but not to the detriment of the code) by putting entire anonymous functions on a single line with a function call.

Source: https://habr.com/ru/post/256127/


All Articles