Swift functions cheatsheet
The function is a self-containing block of code for performing the specific task. The function is a thing, that we use every day. It’s like a building block for our code.
The general form of the Swift function is:
func funcName(paramName: ParamType, ...) -> ResultType {
// Function body goes here...
}
Let’s see it closer using sample:
func doSomethingCool(foo: FooType, withBar bar: BarType, andBuz buz: BuzType) -> ResultType {
// Function body goes here...
}
Notation | Meaning |
---|---|
func |
Denotes that this is a function |
doSomethingCool |
Name of the function |
(foo: FooType, withBar bar: BarType, andBuz buz: BuzType) |
Parameters of the function |
foo , bar , baz |
Parameters variable names |
withBar , andBuz |
Parameters names |
FooType , BarType , BazType |
Parameters types |
ResultType |
The type of the returned result. Can be empty (Void ) |
{} |
Contains function body |
Simplest function
The function can be simple. Let’s check the simplest one.
It starts with func
keyword and named printMessage
, does not have arguments nor return value. It just performs code contained inside curly braces {...}
func printMessage() {
print("Follow the white rabbit!")
}
printMessage()
// > Follow the white rabbit!
Parameters syntax
The function can accept parameters. For example, the following function accepts single String
parameter with the name name
.
func greet(name: String) {
print("Hello, " + name)
}
greet(name: "Neo")
// > Hello, Neo!
The function can accept multiple parameters.
func punchAgentInFace(agentName: String, numTimes count: Int) {
for _ in 0..<count {
print("Punch agent \(agentName)")
}
}
punchAgentInFace(agentName: "Smith", numTimes: 4)
// Prints 4 times
// > Punch agent Smith
If you want to omit parameter names replace them with _
.
That’s how previous function call will look like with second parameter name omitted:
func punchAgentInFace(agentName: String, _ count: Int) {
for _ in 0..<count {
print("Punch agent \(agentName)")
}
}
punchAgentInFace(agentName: "Smith", 4)
// Prints 4 times
// > Punch agent Smith
Named parameters
If you want to make all parameters named, just type desired parameter name before the variable name. Just like in Objective-C. That’s how previous function will look like with named first parameter:
func punchAgentInFace(agent agentName: String, numTimes count: Int) {
for _ in 0..<count {
print("Punch agent \(agentName)")
}
}
punchAgentInFace(agentName: "Smith", numTimes: 4)
// Prints 4 times
// > Punch agent Smith
Parameters with default values
The function can have default parameter values. If you skip parameter in a function call, it will take a default value. Otherwise, it will take passed value.
Parameter name
from the next code sample has default value "Neo"
.
func sayHello(_ name: String = "Neo") {
print("Hello, \(name)!")
}
sayHello()
// > Hello, Neo!
sayHello("Morpheus")
// > Hello, Morpheus!
Variadic parameters
Variadic parameters are handy when parameters count is unknown. Variadic parameter is transformed to Array<ParamType>
.
To mark parameter as variadic use name: <Type>...
syntax. See the following sample:
func inviteToParty(friends: String..., place: String) -> String {
var invitation = "Dear friends! Let me invite you to the party! There will be "
for friend in friends { // `friends` is [String] array
invitation += "\(friend), "
}
return "\(invitation) and me. Place: \(place)"
}
inviteToParty(friends: "Trinity", "Morpheus", place: "Eastern part of Zion")
// > "Dear friends! Let me invite you to the party! There will be Trinity, Morpheus, and me. Place: Eastern part of Zion"
In-out parameters
As mentioned above, variable parameters can only be changed by the function itself. If you need the function to change some parameters from outside the function scope, you should use inout
keyword. Keep in mind that inout
parameters cannot have default values.
func swapAgents(_ agentA: inout String, _ agentB: inout String) {
let temporaryA = agentA
agentA = agentB
agentB = temporaryA
}
var smith = "Smith"
var johnson = "Johnson"
swapAgents(&smith, &johnson)
print("Sminth is now \(smith), Johnson is now \(johnson)")
// > Sminth is now Johnson, Johnson is now Smith
Generic parameters
We can rewrite swapAgents(_:_:)
function in a more general way. Using the following notation we tell that function accepts two parameters of any type, but the type of the parameter a
is always the same as the parameter b
type
func swap1<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
var agentSmith = "Smith"
var agentJohnson = "Johnson"
swap1(&agentSmith, &agentJohnson)
print("Sminth is now \(smith), Johnson is now \(johnson)")
// > Sminth is now Johnson, Johnson is now Smith
var a = 1
var b = 2
swap1(&a, &b)
print("a is now \(a), b is now \(b)")
// > a is now 2, b is now 1
Return values syntax
Functions can return values. It is not required (all the functions above did not return any values). Basically, functions are small programs, which can return results of their work.
As you can see, isThereASpoon(_:)
function returns the single value of Bool
type. In Swift, return value type is separated from function name with ->
symbol.
func isThereASpoon(_ whoAsks: String) -> Bool {
return whoAsks != "Neo"
}
print(isThereASpoon("Neo"))
// > false
print(isThereASpoon("Trinity"))
// > true
Multiple return values
Sometimes we need to receive multiple return values from a function. It is possible. Swift allows us to deal with it in an elegant way. The following code sample shows how to use and access multiple return values:
func distributeToShips(_ crew: [String]) -> (nebuchadnezzar: [String], osiris: [String]) {
var nebuchadnezzarCrew = [String]()
var osirisCrew = [String]()
for i in 0..<crew.count {
if i % 2 == 0 {
nebuchadnezzarCrew.append(crew[i])
} else {
osirisCrew.append(crew[i])
}
}
return (nebuchadnezzarCrew, osirisCrew)
}
let crew = distributeToShips(["Neo", "Morpheus", "Trinity", "Seraph", "Cipher", "Dozer", "Tank"])
print("Nebuchandezzar crew: \(crew.nebuchadnezzar); Osiris crew: \(crew.osiris)")
// > "Nebuchandezzar crew: ["Neo", "Trinity", "Cipher", "Tank"]; Osiris crew: ["Morpheus", "Seraph", "Dozer"]"
Optional tuple
If there is probability, that returning tuple will have no value, we should use an Optional tuple. The function above, rewritten with optional tuple, will look like this:
func distributeToShipsOptional(_ crew: [String] = []) -> (nebuchadnezzar: [String], osiris: [String])? {
if crew.count > 0 {
var nebuchadnezzarCrew = [String]()
var osirisCrew = [String]()
for i in 0..<crew.count {
if i % 2 == 0 {
nebuchadnezzarCrew.append(crew[i])
} else {
osirisCrew.append(crew[i])
}
}
return (nebuchadnezzarCrew, osirisCrew)
}
return nil
}
if let crew = distributeToShipsOptional(["Neo", "Morpheus", "Trinity", "Seraph", "Cipher", "Dozer", "Tank"]) {
print("Nebuchandezzar crew: \(crew.nebuchadnezzar); Osiris crew: \(crew.osiris)")
}
// > "Nebuchandezzar crew: ["Neo", "Trinity", "Cipher", "Tank"]; Osiris crew: ["Morpheus", "Seraph", "Dozer"]"
if let crew = distributeToShipsOptional() {
print("Nebuchandezzar crew: \(crew.nebuchadnezzar); Osiris crew: \(crew.osiris)")
}
// >
Function type
You can pass any function as an argument or use it as a return value of any other function. In Swift, functions are first-class citizens. Function has a type. Function type general form is (argument types) -> return type
. In the example below, both functions, plus(_: _:)
and multiply(_: _:)
has the same type: (Int, Int) -> Int
. calculate(_: _: _:)
function uses proper function depending on the operation passed as argument.
func plus(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiply(_ a: Int, _ b: Int) -> Int {
return a * b
}
// Function type is used as parameter type
func calculate(_ a: Int, b: Int, operation: (Int, Int) -> Int) -> Int {
return operation(a, b)
}
print(calculate(3, b: 7, operation: plus))
// > 10
print(calculate(3, b: 7, operation: multiply))
// > 21
Function as return value
Function can also be used as return type of other function. mathFunction(_:)
returns (Int, Int) -> Int
function, which is used by calculate(_: _: _:)
function from the previous example;
enum Operation {
case plus
case multiply
}
func mathFunction(_ operation: Operation) -> (Int, Int) -> Int {
switch operation {
case .plus:
return plus
case .multiply:
return multiply
}
}
print(calculate(10, b: 3, operation: mathFunction(.plus)))
// > 13
print(calculate(10, b: 3, operation: mathFunction(.multiply)))
// > 30
The type of the function can be named using typealias
keyword. Let’s rewrite our math functions using typealas
.
typealias OperationFunction = (Int, Int) -> Int
func plus1(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiply1(_ a: Int, _ b: Int) -> Int {
return a * b
}
// Function type is used as parameter type
func calculate1(_ a: Int, b: Int, operation: OperationFunction) -> Int {
return operation(a, b)
}
print(calculate1(3, b: 7, operation: plus))
// > 10
print(calculate1(3, b: 7, operation: multiply))
// > 21
Nested functions
Nested functions are functions, used inside the other functions.
typealias Printer = () -> String
func whoWillWin(_ isOptimist: Bool) -> Printer {
func neo() -> String { return "Neo" }
func smith() -> String { return "Smith" }
if isOptimist {
return neo
} else {
return smith
}
}
let iAmGood = true
print(whoWillWin(iAmGood)()) // Notice `functionName(param)()` syntax. Remember, `whoWillWin(_:)` returns function!
// > Neo
Conclusion
Functions in Swift are powerful and flexible. Different syntactical possibilities can be used to improve code informativity and reduce clatter.