10 Essential Swift Interview Questions *

Toptal sourced essential questions that the best Swift developers and engineers can answer. Driven from our community, we encourage experts to submit questions and offer feedback.

Hire a Top Swift Developer Now
Toptal logois an exclusive network of the top freelance software developers, designers, finance experts, product managers, and project managers in the world. Top companies hire Toptal freelancers for their most important projects.

Interview Questions

1.

Consider the following code:

var array1 = [1, 2, 3, 4, 5]
var array2 = array1
array2.append(6)
var len = array1.count

What’s the value of the len variable, and why?

View answer

The len variable is equal to 5, meaning that array1 has 5 elements, whereas array2 has 6 elements:

array1 = [1, 2, 3, 4, 5]
array2 = [1, 2, 3, 4, 5, 6]

When array1 is assigned to array2, a copy of array1 is actually created and assigned.

The reason is that swift arrays are value types (implemented as structs) and not reference types (i.e. classes). When a value type is assigned to a variable, passed as argument to a function or method, or otherwise moved around, a copy of it is actually created and assigned or passed. Note that swift dictionaries are also value types, implemented as structs.

Value types in swift are:

  • structs (incl. arrays and dictionaries)
  • enumerations
  • basic data types (boolean, integer, float, etc.)
2.

Consider the following code:

let op1: Int = 1
let op2: UInt = 2
let op3: Double = 3.34
var result = op1 + op2 + op3

Where is the error and why? How can it be fixed?

View answer

Swift doesn’t define any implicit cast between data types, even if they are conceptually almost identical (like UInt and Int).

To fix the error, rather than casting, an explicit conversion is required. In the sample code, all expression operands must be converted to a common same type, which in this case is Double:

var result = Double(op1) + Double(op2) + op3
3.

Consider the following code:

var defaults = NSUserDefaults.standardUserDefaults()
var userPref = defaults.stringForKey("userPref")!
printString(userPref)

func printString(string: String) {
    println(string)
}

Where is the bug? What does this bug cause? What’s the proper way to fix it?

View answer

The second line uses the stringForKey method of NSUserDefaults, which returns an optional, to account for the key not being found, or for the corresponding value not being convertible to a string.

During its execution, if the key is found and the corresponding value is a string, the above code works correctly. But if the key doesn’t exist, or the corresponding value is not a string, the app crashes with the following error:

fatal error: unexpectedly found nil while unwrapping an Optional value

The reason is that the forced unwrapping operator ! is attempting to force unwrap a value from a nil optional. The forced unwrapping operator should be used only when an optional is known to contain a non-nil value.

The solution consists of making sure that the optional is not nil before force-unwrapping it:

let userPref = defaults.stringForKey("userPref")
if userPref != nil {
    printString(userPref!)
}

An even better way is by using optional binding:

if let userPref = defaults.stringForKey("userPref") {
    printString(userPref)
}

Apply to Join Toptal's Development Network

and enjoy reliable, steady, remote Freelance Swift Developer Jobs

Apply as a Freelancer
4.

The String struct doesn’t provide a count or length property or method to count the number of characters it contains. Instead a global countElements<T>() function is available. When applied to strings, what’s the complexity of the countElements function:

  • O(1)
  • O(n)

and why?

View answer

Swift strings support extended grapheme clusters. Each character stored in a string is a sequence of one or more unicode scalars that, when combined, produce a single human readable character. Since different characters can require different amounts of memory, and considering that an extreme grapheme cluster must be accessed sequentially in order to determine which character it represents, it’s not possible to know the number of characters contained in a string upfront, without traversing the entire string. For that reason, the complexity of the countElements function is O(n).

5.

In Swift enumerations, what’s the difference between raw values and associated values?

View answer

Raw values are used to associate constant (literal) values to enum cases. The value type is part of the enum type, and each enum case must specify a unique raw value (duplicate values are not allowed).

The following example shows an enum with raw values of type Int:

enum IntEnum : Int {
    case ONE = 1
    case TWO = 2
    case THREE = 3
}

An enum value can be converted to its raw value by using the rawValue property:

var enumVar: IntEnum = IntEnum.TWO
var rawValue: Int = enumVar.rawValue

A raw value can be converted to an enum instance by using a dedicated initializer:

var enumVar: IntEnum? = IntEnum(rawValue: 1)

Associated values are used to associate arbitrary data to a specific enum case. Each enum case can have zero or more associated values, declared as a tuple in the case definition:

enum AssociatedEnum {
    case EMPTY
    case WITH_INT(value: Int)
    case WITH_TUPLE(value: Int, text: String, data: [Float])
}

Whereas the type(s) associated to a case are part of the enum declaration, the associated value(s) are instance specific, meaning that an enum case can have different associated values for different enum instances.

6.

Swift defines the AnyObject type alias to represent instances of any reference type, and it’s internally defined as a protocol.

Consider the following code:

var array = [AnyObject]()
struct Test {}
array.append(Test())

This code generates a compilation error, with the following error message:

Type 'Test' does not conform to protocol 'AnyObject'

The failure is obvious because a struct is a value and not a reference type, and as such it doesn’t implement and cannot be cast to the AnyObject protocol.

Now consider the following code:

var array = [AnyObject]()
array.append(1)
array.append(2.0)
array.append("3")
array.append([4, 5, 6])
array.append([7: "7", 8: "8"])

struct Test {}
array.append(Test())

The array array is filled in with values of type respectively int, double, string, array and dictionary. All of them are value types and not reference types, and in all cases no error is reported by the compiler. Why?

View answer

The reason is that swift automatically bridges:

  • number types to NSNumber
  • strings to NSString
  • arrays to NSArray
  • dictionaries to NSDictionary

which are all reference types.

7.

Consider the following code:

class Master {
    lazy var detail: Detail = Detail(master: self)
    
    init() {
        println("Master init")
    }
    
    deinit {
        println("Master deinit")
    }
}

class Detail {
    var master: Master
    
    init(master: Master) {
        println("Detail init")
        self.master = master
    }
    
    deinit {
        println("Detail deinit")
    }
}

func createMaster() {
    var master: Master = Master()
    var detail = master.detail
}
    
createMaster()

What is the bug and how does it affect memory? How can it be fixed?

View answer

There is a strong reference cycle between Master and Detail, with Master creating an instance of Detail and storing a reference to it, and Detail storing a reference to the instance of its Master creator. In both cases, references are strong, which means that none of the 2 instances will ever be deallocated, causing a memory leak.

To solve the problem it’s necessary to break at least one of the 2 strong relationships, by using either the weak or unowned modifier. The differences between the 2 modifiers is:

  • unowned: the reference is assumed to always have a value during its lifetime - as a consequence, the property must be of non-optional type.
  • weak: at some point it’s possible for the reference to have no value - as a consequence, the property must be of optional type.

In the above code example, the proper solution is to define in Detail the reference to Master as unowned:

class Detail {
    unowned var master: Master
    ...
}
8.

The following code snippet results in a compile time error:

struct IntStack {
  var items = [Int]()
  func add(x: Int) {
    items.append(x) // Compile time error here.
  }
}

Explain why a compile time error occurs. How can you fix it?

View answer

Structures are value types. By default, the properties of a value type cannot be modified from within its instance methods.

However, you can optionally allow such modification to occur by declaring the instance methods as ‘mutating’; e.g.:

struct IntStack {
  var items = [Int]()
  mutating func add(x: Int) {
    items.append(x) // All good!
  }
}
9.

Consider this code:

let d = ["john": 23, "james": 24, "vincent": 34, "louis": 29]
let x = d.sort{ $0.1 < $1.1 }.map{ $0.0 }

What is the type of x? And what is its value?

View answer

x is of type [String] and of value ["john", "james", "louis", "vincent"].

10.

Consider the following code:

struct Planet {
    let name: String
    let distanceFromSun: Double
}

let planets = [
    Planet(name: "Mercury", distanceFromSun: 0.387),
    Planet(name: "Venus", distanceFromSun: 0.722),
    Planet(name: "Earth", distanceFromSun: 1.0),
    Planet(name: "Mars", distanceFromSun: 1.52),
    Planet(name: "Jupiter", distanceFromSun: 5.20),
    Planet(name: "Saturn", distanceFromSun: 9.58),
    Planet(name: "Uranus", distanceFromSun: 19.2),
    Planet(name: "Neptune", distanceFromSun: 30.1)
]

let result1 = planets.map { $0.name }
let result2 = planets.reduce(0) { $0 + $1.distanceFromSun }

What are the types and values of the result1 and result2 variables? Explain why.

View answer

result1 is an array of strings, containing the list of the planet names result2 is a double, calculated as the sum of the distance of all planets

The map method of the Array<T> struct type performs a transformation of the source array into an array of another type, whose values are obtained by executing the closure passed as parameter to each element of the array. In the above code, the closure returns the name property, so the map method in the above code returns an array of planet names.

Given an initial value and a closure, the reduce method of the Array<T> struct type returns a single value obtained by recursively applying the closure to each element of the array. The closure takes the value calculated at the previous step (or the initial value if it’s the first iteration) and the current array element, and is expected to return a value of the same type of the initial value.

In the above code, the closure returns the sum of what calculated at the previous step, plus the value of the distanceFromSun property for the current element. The end result is the sum of the distances of all planets.

There is more to interviewing than tricky technical questions, so these are intended merely as a guide. Not every “A” candidate worth hiring will be able to answer them all, nor does answering them all guarantee an “A” candidate. At the end of the day, hiring remains an art, a science — and a lot of work.

Why Toptal

Tired of interviewing candidates? Not sure what to ask to get you a top hire?

Let Toptal find the best people for you.

Hire a Top Swift Developer Now

Our Exclusive Network of Swift Developers

Looking to land a job as a Swift Developer?

Let Toptal find the right job for you.

Apply as a Swift Developer

Job Opportunities From Our Network

Submit an interview question

Submitted questions and answers are subject to review and editing, and may or may not be selected for posting, at the sole discretion of Toptal, LLC.

* All fields are required

Looking for Swift Developers?

Looking for Swift Developers? Check out Toptal’s Swift developers.

Josip Petrić

Freelance Swift Developer
CroatiaFreelance Swift Developer at Toptal Since July 25, 2016

As a software engineer with over a decade of experience, Josip has developed a keen sense of building scalable, maintainable, and user-friendly applications. His platform of choice is iOS for which he has designed and developed a wide range of applications, from simple ones to complex, large-scale applications. Josip is a proven team leader and a team player with exemplary communication and social skills.

Show More

Ryan Bradley Lons

Freelance Swift Developer
United StatesFreelance Swift Developer at Toptal Since January 7, 2015

Ryan is a senior-level iOS and web developer passionate about creating amazing user interfaces and experiences. He's very comfortable working anywhere in the development stack and has 10+ years of doing it. He's well-spoken, very easy to communicate with, quick to respond, and excels at figuring out optimal solutions for any challenge you present. Ryan has an entrepreneurial drive and understands the challenges startups face.

Show More

Josh Reynolds

Freelance Swift Developer
NetherlandsFreelance Swift Developer at Toptal Since May 10, 2016

With 15+ years of success building great digital products around the world, Josh leads with compassion and by example. He will jump in the trenches with the rest of the team whenever needed and bring clear strategy to help us steer safely through the turbulent waters of the digital sea. Josh's tools of choice are evidence, empathy, clear and dynamic communication, and a growth mindset.

Show More

Toptal Connects the Top 3% of Freelance Talent All Over The World.

Join the Toptal community.

Learn more