Swift Functions

In this article, we will explain user-defined functions in Swift.

What Are User-Defined Functions in Swift?

In programming, a function is a block of code that performs a specific task and can be called by name.

Parameters are the values passed from the caller to the function at runtime, and the variables inside the function that receive those values.


Swift provides many built-in functions that you can call and use when needed. For example, print() is a commonly used built-in library function for output.

Like other programming languages, Swift allows you to define your own functions (user-defined functions) that group together specific operations, which can then be called whenever needed.

Just like built-in functions, user-defined functions can take parameters and return values.


If you find yourself writing the same code repeatedly, it's often better to define a user-defined function and call it instead.

Now, let's dive deeper into user-defined functions in Swift.


Defining Functions in Swift

In Swift, you define a function using the func keyword as follows:

func functionName(param1: Type1, param2: Type2, ...) -> ReturnType {
    // function body
    ...
    return returnValue
}

Parameters and return values are optional if not needed.

Defining a function alone does not execute its code. The function runs only when it is called.

You can call a user-defined function just like a built-in function, for example: functionName(param1: value1, param2: value2).


If you don't want to require parameter labels when calling the function, you can add an underscore (_) in the parameter definition:

func functionName(_ param1: Type1, _ param2: Type2, ...) -> ReturnType {
    // function body
    ...
    return returnValue
}

For example, here's a simple greet function with no parameters that prints "Hello!":

func greet() {
    print("Hello!")
}

greet()

The result will be as follows. The call greet() executes the function, which then runs print("Hello!").

Hello!

Function Parameters in Swift

Previously, we defined a function with no parameters. Now let's define one with parameters.

Here, we add firstName and lastName parameters to greet() and print them:

func greet(firstName: String, lastName: String) {
    print("Hello! I'm \(firstName) \(lastName).")
}

greet(firstName: "James", lastName: "Williams")
greet(firstName: "John", lastName: "Smith")

The output will change based on the argument values passed:

Hello! I'm James Williams.
Hello! I'm John Smith.

Default Parameter Values in Swift Functions

Parameters in user-defined functions are normally required. If you don't pass a value, you'll get an error.

However, you can assign default values to parameters, which allows you to omit them when calling the function.


For example, here's a function that adds four numbers, with default values for the third and fourth parameters:

func add(value1: Int = 1, value2: Int, value3: Int = 0, value4: Int = 0) {
    print(value1 + value2 + value3 + value4)
}

add(value1: 1, value2: 2)
add(value1: 1, value2: 2, value3: 3)
add(value1: 1, value2: 2, value4: 4)

The results show that parameters with defaults can be omitted, and their default values are used:

3
6
7

Variadic Parameters in Swift Functions

If the number of parameters is unknown, you can make them variadic by adding ... after the type.

This means the parameter is received as an array, allowing you to use indexing or loops to access each argument.


For example, here's a function that sums any number of integers:

func add(values: Int...) {
    var total = 0
    for value in values {
        total += value
    }
    print("Total: \(total)")
}

add(values: 1, 2, 3)
add(values: 1, 2, 3, 4, 5)

The results show that any number of integer arguments can be passed:

Total: 6
Total: 15

Return Values in Swift Functions

To return a value from a function, specify the type after -> and use a return statement.

For example, here's the previous sum function modified to return the total:

func add(values: Int...) -> Int {
    var total = 0
    for value in values {
        total += value
    }
    return total
}

let total = add(values: 1, 2, 3, 4, 5)
print("Total: \(total)")

The result confirms that add() returns the total:

Total: 15

Returning Multiple Values from a Function

You can return multiple values from a Swift function using a tuple.

For example, if you want to take a string as name, split it at " ", and return the first string as lastName and the second string as firstName only when it is separated into two, you can do the following:

func splitName(name: String) -> (lastName: String, firstName: String) {
    let names = name.split(separator: " ")
    if names.count == 2 {
        return (String(names[0]), String(names[1]))
    } else {
        return ("", "")
    }
}

let (lastName, firstName) = splitName(name: "Sarah Smith")
print("lastName = \(lastName), firstName = \(firstName)")

The output will be:

lastName = Sarah, firstName = Smith

You can also capture the tuple in a single variable as let n = splitName(name: "Sarah Smith") and access its elements like n.lastName and n.firstName.


Passing Parameters by Reference with inout

Whether function parameters can be modified inside the function depends on whether the type is a reference type or a value type.

For example, classes are reference types. Even if defined with let, the reference itself is fixed but properties can still be changed, so updates inside the function also affect the caller.

Swift Function Example 1


However, basic types like Int, String, Double, Array, Struct, Enum, Tuple, and Dictionary are all value types in Swift.

Trying to modify them directly inside a function causes an error, as value types are immutable by default in this context.


Sometimes, you may want to pass a value type parameter by reference so that changes inside the function are reflected outside.

To do this, add the inout keyword before the parameter type and prefix the argument with & when calling the function.


For example, here's a modified splitName function that overwrites the input with "Invalid" if it cannot split properly:

func splitName(name: inout String) -> (lastName: String, firstName: String) {
    let names = name.split(separator: " ")
    if names.count == 2 {
        return (String(names[0]), String(names[1]))
    } else {
        name = "Invalid"
        return ("", "")
    }
}

var name = "Saki"
print("name before: \(name)")

let nameSplit = splitName(name: &name)

print("name after: \(name)")

The result shows that the variable name is modified after the function call:

name before: Saki
name after: Invalid

That wraps up our explanation of user-defined functions in Swift.