Swift Interview Questions in 2023: This Is What They Ask

Here’s a list of 50 Swift interview questions and answers.

These questions focus on Swift programming and iOS app development. You need to know the answers to these before you get a chance to show your skills in front of a job interviewer.

Also, feel free to use these Swift interview questions to practice for an exam.

These interview questions are in no particular order.

1. What Causes an Error in This Piece of Code? How Could You Fix It?

let n1: Int = 1
let n2: Float = 2.0
let n3: Double = 3.34

var result = n1 + n2 + n3

Answer:

In Swift, implicit type casting between two data types is not possible.

In the code above, you’re trying to add three elements together, each of which represents a different data type.

To fix this, you need to convert each value to the same data type. For example:

var result = Double(n1) + Double(n2) + n3

2. What is the Value of Variable Len? Why?

var arr1 = [1, 2, 3]
var arr2 = arr1

arr2.append(4)

var len = arr1.count

Answer:

The value of len is 3, i.e. the number of elements in arr1 is 3. This is because assigning arr1 to arr2 actually means that a copy of arr1 is assigned to arr2, so the arr1 is not affected.

In Swift, all the basic data types (booleans, integers, etc.), enums, and structs are value types by nature.

Arrays are value types too. When moving a value type around in Swift, you’re essentially working with a copy of it. For example, when passing a value type as an argument to a function, a copy of it is created, so whatever the function does is not reflected in the original value.

3. What’s the Issue and How Can You Fix It?

Consider this piece of code that tries to retrieve a theme color from the local storage of an iOS device:

var color = UserDefaults.standard.string(forKey: "themeColor")!
print(color)

Can you spot the mistake and fix it?

Answer:

The first line retrieves a theme color from the user defaults. This method, however, returns an optional (because the themeColor might not be defined). If the key is not found, a nil is returned the above code crashes with:

fatal error: unexpectedly found nil while unwrapping an Optional value

This happens as the first line is using ! to force unwrap the optional, which is now a nilForce unwrapping should be only used when you’re 100% sure the value is not nil.

To fix this, you can use optional binding to check if the value for the key is found:

if let color = defaults.stringForKey("themeColor") {
print(color)
}

4. What Potential Improvements Can You See?

You are reviewing a pull request and encounter this method:

func turnTo(direction: String){
    if direction == "North" {
        northAction()
    } else if direction == "East" {
        eastAction()
    } else if direction == "South" {
        southAction()
    } else if direction == "West" {
        westAction()
    } else {
        print("No valid direction specified")
    }
}

What improvements can you suggest to the writer of the code?

Answer:

Even though this code might work, there are two things that should be considered.

  • Using hard-coded strings like (e.g."West") is a bad idea. What if someone miss-spells it? To remedy this issue, the hard-coded strings should be abandoned and an enumeration should be created instead.
  • Also, how about using a switch statement instead of a lengthy if-else statement?

With these improvements, the code becomes type-safer and readable:

enum Direction {
    case North
    case East
    case South
    case West
}

func turnTo(direction: Direction){
    switch direction {
    case .North: northAction()
    case .East: eastAction()
    case .South: southAction()
    case .West: westAction()
    default:
        print("No valid direction specified")
    }
}

5. What Are Enumerations in Swift?

An enumeration is a group of related values.

Enumerations make it possible to write type-safe code.

enum Direction {
case North
case East
case South
case West
}

Now, in your code, you can call Direction.North, for example, instead of using a mystic string "North" (that could easily be misspelled and cause annoying bugs).

You can find more information about enumerations in Swift in this article.

6. What is an Optional in Swift? How Can You Create One?

An optional is a type that can store either a value or a nil. You can create an optional by adding a question mark ? after any type:

var number: Int? = 10

7. What is typealias in Swift? How Do You Create One?

Typealias, as the name suggests, is an alias for an existing data type.

You can create one like this:

typealias Weight = Float

Now you can use Weight instead of Float:

let mass1: Weight = 150.0
let mass2: Weight = 220.0

let total: Weight = mass1 + mass2

8. Name Some Advantages of Using Swift

To name a few:

  • Swift is a type-safe language
  • It has closure support
  • It has optional type support
  • It has built-in error handling
  • It has pattern-matching support

9. Name the 5 Control Transfer Statements and Describe How to Use Them

Five control transfer statements are:

  • Break
  • Continue
  • Fallthrough
  • Throw
  • Return

Control transfer statements change the order in which your code runs.

For example, you can use a control transfer statement break to end the execution of a for-loop when deemed unnecessary to continue looping:

for choice in choices:
if isCorrect(choice):
print("Correct choice found!")
break

10. Suggest a Small Refactoring to This Code

if age < 18 {
driveCar()
} else {
doNotDrive()
}

This expression is clean and works well — but can you suggest a minor refactoring improvement to make it even better?

Answer:

You can use the ternary conditional operator to convert this expression into a one-liner, which in this case does not compromise readability but improves it.

age < 18 ? driveCar() : doNotDrive()

11. How Can You Improve Code Readability

In our company, we have 20 developers and 20 unique coding styles. How might we enforce some common coding styles/best practices?

Answer:

Start using a linter, such as Swiftlint. A linter is an easy-to-setup tool that checks and fixes your mistakes and enforces best practices and conventions on your behalf.

You can use the linter’s default guidelines, but you can also configure the linter to match your company’s preferences.

12. What Is a Completion Handler in Swift?

Completion handlers are closures in action.

Suppose you perform a time-consuming task, such as a network request, and you want to do something immediately after the request completes. But you definitely don’t want to waste resources by checking multiple times if the process is ongoing or not.

This is where completion handlers are used. A completion handler is a closure that “calls you back” as soon as the time-consuming process completes.

Read more about closures and how to pass a function as a parameter.

13. How to Test an App without a Physical Device

If you don’t have an iOS device, you can use Apple’s iOS device simulators to test your apps on Mac.

14. What Does init() Do in Swift?

The init() method is used to initialize an instance.

Initialization means you prepare an instance (of a class, structure, or enumeration) for use.

In the initialization process, you set initial values for each property of the instance. You may also perform some other preparations before the instance is ready for use.

15. Let vs Var in Swift?

In Swift, you can use let to create a constant (a value that cannot be changed) and var to create a variable (a value that can be modified later).

You can find some additional details in this article.

16. What is a PLIST?

PLIST, or property list, is a dictionary of key-value pairs that are used to store data in your project’s file system. For example, info.plist.

17. What Are Protocols in Swift? Give an Example

A protocol is a code contract. It acts as a blueprint for properties, methods, etc. It describes how the type conforming to it must behave.

You cannot create instances of protocols. Rather, you can make e.g. a class conform to a protocol.

Here is an example protocol that describes an animal:

protocol Animal {
    var name: String { get set }
    var color: String { get set }
    func makeSound()
}

Let’s create classes Cat and Dog that both conform to the Animal protocol. It is thus required that they both implement the behavior described in the Animal protocol — that is, variables namecolor and the makeSound() method:

class Cat: Animal {
    var name = "Luna"
    var color = "gray"
    func makeSound() {
        print("Meow!")
    }
}

class Dog: Animal {
    var name = "Charlie"
    var color = "black"
    func makeSound() {
        print("Woof!")
    }
}

18. What Is the Double Question Mark Operator?

The double question mark operator ?? is known as the nil coalescing operator. It returns the value on the left-hand side if it’s not nil. If the left-hand side is nil then it returns the value on the right-hand side.

Nil coalescing can be used as a shorthand for checking if an optional value is nil. For example, you can replace this:

var name: String?

if name != nil {
    print(name)
} else {
    print("N/A")
}

With this:

print(name ?? "N/A")

19. What Is the Guard Statement?

A guard statement is used to transfer program control out of scope. The guard statement is similar to the if statement, but it runs only when some conditions are not met.

For example, a guard statement used to exit a function:

func myFun() {
    guard false else {
         print("This block is run")
         return
    }
    print("This is never run")
}

myFun()

Output:

This block is run

Learn more about the guard keyword by reading this article.

20. What Are the Three Primary Collection Types in Swift?

  • Arrays: An array is an ordered collection of values.
  • Sets: A set is an unordered collection of values.
  • Dictionaries: A Dictionary is an unordered collection of key-value pairs.

21. What Is Defer in Swift?

You can use the defer method to execute code before exiting the scope. As an example, let’s print something right before the function’s execution completes:

func printStuff() {
    defer { 
        print("I some printed numbers and now I exit the scope")
    }
    print("4")
}

printStuff()

// Output:
// 4
// I printed numbers and now I exit the scope

Deferring is commonly used when opening and closing context within a scope — e.g. when accessing files.

22. Can You Swap Two Variables Without a Third Helper Variable?

This is a classic Swift interview question.

Yes, it is possible.

With tuple destructuring, you can solve the problem like this:

var a = 1
var b = 2

(a, b) = (b, a)

23. What’s the Difference Between Structures and Classes?

  • Structures are value types, whereas classes are reference types.
  • Structures don’t support inheritance, classes do.
  • In class, we can create an instance with let keywords and attempt to mutate its property, whereas there is no mutability in structures.
  • Structures do not support typecasting, but classes do.

24. What is Optional Chaining?

Optional chaining means you can safely call a property of something that may be nil.

Optional chaining works, as the name suggests, by chaining one or more optional values with a question mark operator ?, like this:

something?.someValue?.someMethod()

If nil is encountered at any point in the above chain, the app won’t crash — instead, a nil is returned.

25. What Is Optional Binding?

Optional binding checks if an optional contains a value or not. If the optional does have a value, optional binding makes that value temporarily available:

As an example, the following code checks if the name is nil or not. If it’s not, a temporary constant realName is created and the value name is assigned to it.

var name: String? = "Charles"

if let realName = name {
    print (realName)
}

Output:

Charles

26. Explain the MVC Architecture

MVC (Model-View-Controller), is a software architecture for developing iOS apps. It’s one of iOS app development’s fundamental concepts.

Multiple iOS frameworks use the MVC.

The idea of MVC is to pass data from one place to another. It means any object falls into one of these three categories:

  • Model: A model represents the app’s data. It stores info, such as products in a store. A model manages the state of the application.
  • View: A view is responsible for showing and interacting with the UI. For example, a view renders a table of products for your app’s user.
  • Controller: The controller is what glues the model and the view. It’s responsible for controlling the logic that goes between the two.

27. What Is an In-Out Parameter in Swift?

An inout parameter allows you to change the value of a parameter inside the function.

To make a parameter in-out, use the inout keyword in front of the parameter type.

To pass a variable as an in-out, use & in front of its name.

For example:

func change(_ number: inout Int){
    number = 2
}

var number = 1

change(&number)
print(number)

// Output: 
// 2

28. What Is a Tuple? Demonstrate How to Work with Tuples

A tuple is a value that can be used to bundle multiple values together, for example, as a pair.

The values of the tuple do not need to be of the same type.

You can create a tuple by comma-separating values inside parentheses.

For example:

var coordinates3D = (1.0, 2.0, 5.0)

To access a value inside a tuple, use the dot notation and an index:

let xPos = coordinates3D.0

Tuples can also be created so that each value has a name:

var coordinates3D = (x: 1.0, y: 2.0, z: 5.0)

In this case, you can access a specific value of the tuple by its name:

let xPos = coordinates3D.x

29. What Are Swift Messages?

Swift Messages is a library used to display messages as a status bar at the top or at the bottom of the iOS device’s screen.

30. Is It Possible to Give a Default Value to a Function Parameter?

It is possible to give a default value for a parameter:

func eat(food: String = "spaghetti") {
print("Yum! I ate some good \(food).")
}

31. What Are Generics? Give an Example of Using Generics

Generics allows you to write flexible and reusable code that can work with any data type.

Imagine you’re writing a 3D vector structure, but you want to be able to create vectors using integers, floats, and doubles. You definitely don’t want to write the same code for each data type separately.

This is where you can use generics.

For example, you can create a generic type for parameters (to represent any type) using a letter e.g. T like this:

struct Vec3D<T> {
    let x, y, z: T
    init(x: T, y: T, z: T) {
        self.x = x
        self.y = y
        self.z = z
    }
}

let intVector = Vec3D(x: 1, y: 2, z: 5)
let floatVector = Vec3D(x: 1.0, y: 2.0, z: 5.0)

32. In the Following, What Is the Pounds Property Known as?

class Weight {
    var kilograms: Float = 0.0
    var pounds: Float {
        get {
            return (kilograms * 2.205)
        }
        set(newWeight) {
            kilograms = newWeight / 2.205
        }
    }
}

let weight = Weight()
weight.kilograms = 100

print(weight.pounds) // prints '220.5'
weight.pounds = 315
print(weight.kilograms) // prints '142.85715'

Answer:

The pounds property is also known as a computed property.

In Swift, computed properties are not stored in the object. A computed property means that its value gets computed “on-demand” only when trying to access it. You can create computed properties using get and (optional) set methods.

  • The get method performs the “on-demand” computation when weight.pounds is called.
  • The set method updates kilograms when pounds are updated. (Notice that set method is optional, and you don’t need such a method in order to create a computed property.)

33. What is the difference between == and === Operators?

  • == is the equality operator.
  • === is the identity operator.

The equality operator == is used to check if two Equatable types are equal:

"Hello" == "Hello"
10.0 == 5.0 + 5.0

The identity operator === can be used to check if two classes are identical i.e. if they point to the same memory address. Let’s see an example:

class Fruit {
    var name = "Banana"
}

let fruit1 = Fruit()
let fruit2 = fruit1 // fruit2 now points to same address as fruit

1fruit1 === fruit2 // true

Learn more about what is the difference between == and === here.

34. What Are Extensions?

In Swift, you can use extensions to add functionality to an existing type.

In Swift, you can create an extension by using the extension keyword:

extension SomeExistingType {
    // add new functionality here
}

35. What Is a Nested Function?

A nested function is a combination of a function inside a function:

func outer() {
func inner() {
// Do something here
}
}

36. How Do You Create a Base Class in Swift?

You can create a base class by simply defining a class without a superclass.

37. What Is Force Unwrapping? When Should You Use It?

Force unwrapping tries to convert an optional to a value regardless of it contains a value or not.

Force unwrapping is unsafe because if the optional is nil and you try to unwrap it, it triggers an error that crashes the app. Thus, it should be avoided unless you’re 100% sure the optional is not nil.

38. List Benefits of Higher-Order Functions.

  • They provide flexibility.
  • They are useful in async calls where regular functions can’t be used.
  • They sometimes improve the quality of code and make it shorter and more concise.

39. Fileprivate vs Private?

  • fileprivate property can be read anywhere in the same Swift file but not outside of it.
  • private property can only be read inside the type in which it was declared (as well as in the extensions of that type in the same file).

Learn more about private and fileprivate here.

40. What Functions Are in Swift?

A function makes it possible to define reusable blocks of code. A function can perform a task that’s part of your program.

Usually, functions take some values that they can work with.

41. Nil vs None in Swift?

There is no difference between the two:

nil == .none // returns true

The only “difference” is using nil is more common than using none.

42. What Is a Dictionary in Swift?

A dictionary is a basic collection type in Swift. It can be used to store key-value pairs.

You can easily access a value by knowing a key:

let dict = ["a": 1, "b": 2]
let valueOfA = dict["a"]

43. What Does the Mutating Keyword Do?

You can use the mutating keyword to allow changing properties of a structure in a method by marking that particular method mutating.

For example:

struct Fruit {
    var type: String
    mutating func convertToBanana() {
        self.type = "Banana"
    }
}

var fruit = Fruit(type: "Apple")
fruit.convertToBanana()

print(fruit.type) // prints "Banana"

By default, this is not possible for value types (structures and enumerations) but it is possible for reference types (classes).

44. Can You Fix the Issue in this Code?

This code below throws a compiler error. What is wrong? How can you fix it?

struct Apple {}

func pick(apple: Apple?) {
  guard let apple = apple else {
    print("No apple found!")
  }   
  print(apple)
}

Answer:

The else block of a guard statement requires an exit path.

You can, for example, use return to provide it with one:

struct Apple {}

func pick(apple: Apple?) {
  guard let apple = apple else {
    print("No apple found!")
    return
  }   
  print(apple)
}

45. What Is a Deinitializer? How to Create One?

A deinitializer is run before a class instance is deallocated.

You can create a deinitalizer by using the deinit keyword.

This method is useful only if you need to do some housekeeping before deallocating a class instance. Most of the time it’s enough to let Swift handle it automatically on your behalf.

Here is an example of a deinitializer that sets number back to 0 when an instance of Example is deallocated.

var number = 15

class Example {
    init() {
       number *= 10
    }
    
    deinit {
        number = 0
    }
}

46. What’s the Difference Between Functions and Methods?

There is a small difference between a function and a method. Both are reusable chunks of code, however, methods belong to classes, structures, or enumerations but functions don’t.

47. How to Disallow a Class from Being Inherited?

By making the class a final class by using the final keyword. For example:

final class Animal {
let name = "I'm a furry animal"
}

Learn more about final classes and their benefits here.

48. What Are Lazy Variables? When Should You Use One?

A lazy variable‘s initial value is computed when calling it for the first time. Lazy variables can be used to optimize code by not doing unnecessary work before needed.

For example:

lazy var tallest: Person? = {
return people.max(by: { $0.height < $1.height })
}()

To learn more about lazy variables, check this article.

49. What Is an Autoclosure in Swift? How and When Should You Use One?

An autoclosure wraps a function argument into a closure.

When an autoclosure is called, it returns the value of the expression wrapped inside.

Autoclosure is nothing but a syntactical convenience for writing cleaner code.

Sometimes, it’s syntactically convenient to use autoclosures when working with a function that takes a closure argument.

This is because autoclosure lets you omit using curly braces {}.

This can make the code more readable.

However, keep in mind what Apple says about using autoclosures:

It’s common to call functions that take autoclosures, but it’s not common to implement that kind of function.

Here’s an example of an autoclosure simplifying the code. The first snippet is using a regular closure, and the second one is using autoclosure. Take a look at how the I_will function call becomes more readable in the second one:

func I_will(_ perform_action: () -> Void) {
    perform_action()
}

I_will({
    print("Hello, world!")
})
func I_will(_ perform_action: @autoclosure () -> Void) {
    perform_action()
}

I_will(print("Hello, world"))

As you can see, the I_will function call does not require using curly braces anymore.

50. What is Missing in This Piece of Code?

enum Example {
  case something(Int, Example)
}

Answer:

It’s possible to create recursive enumerations like the above in Swift. Below is an abstract example — however, using recursive enumerations is disabled by default, you need to enable it using the indirect keyword:

enum Example {
  indirect case something(Int, Example)
}

Thanks for reading! Best of luck with your interview!

Scroll to Top