Swift Interview Questions and Answers
In this tutorial, you’ll work through a series of Swift-specific interview questions and answers. By Bill Morefield.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Swift Interview Questions and Answers
30 mins
- Beginner Written Questions
- Question #1
- Question #2
- Question #3
- Question #4
- Beginner Verbal Questions
- Question #1
- Question #2
- Question #3
- Question #4
- Question #5
- Intermediate Written Questions
- Question #1
- Question #2
- Question #3
- Question #4
- Question #5
- Question #6
- Intermediate Verbal Questions
- Question #1
- Question #2
- Question #3
- Question #4
- Advanced Written Questions
- Question #1
- Question #2
- Question #3
- Question #4
- Advanced Verbal Questions
- Question #1
- Question #2
- Question #3
- Question #4
- Where to Go From Here?
Question #3
Consider the following code that defines Pizza
as a struct and Pizzeria
as a protocol with an extension that includes a default implementation for makeMargherita()
:
struct Pizza {
let ingredients: [String]
}
protocol Pizzeria {
func makePizza(_ ingredients: [String]) -> Pizza
func makeMargherita() -> Pizza
}
extension Pizzeria {
func makeMargherita() -> Pizza {
return makePizza(["tomato", "mozzarella"])
}
}
You'll now define the restaurant Lombardi’s
as follows:
struct Lombardis: Pizzeria {
func makePizza(_ ingredients: [String]) -> Pizza {
return Pizza(ingredients: ingredients)
}
func makeMargherita() -> Pizza {
return makePizza(["tomato", "basil", "mozzarella"])
}
}
The following code creates two instances of Lombardi's. Which of the two will make a margherita with basil?
let lombardis1: Pizzeria = Lombardis()
let lombardis2: Lombardis = Lombardis()
lombardis1.makeMargherita()
lombardis2.makeMargherita()
[spoiler title="Answer"]
They both do. The Pizzeria
protocol declares the makeMargherita()
method and provides a default implementation. The Lombardis
implementation overrides the default method. Since you declare the method in the protocol in both cases, you'll invoke the correct implementation at runtime.
What if the protocol doesn't declare the makeMargherita()
method but the extension still provides a default implementation, like this?
protocol Pizzeria {
func makePizza(_ ingredients: [String]) -> Pizza
}
extension Pizzeria {
func makeMargherita() -> Pizza {
return makePizza(["tomato", "mozzarella"])
}
}
Here, only lombardis2
would make the pizza with basil, whereas lombardis1
would make a pizza without it, because it would use the method defined in the extension.
[/spoiler]
Question #4
The following code has a compile time error. Can you spot it and explain why it happens? What are some ways you could fix it?
struct Kitten {
}
func showKitten(kitten: Kitten?) {
guard let k = kitten else {
print("There is no kitten")
}
print(k)
}
Hint: There are three ways to fix the error.
[spoiler title="Answer"]
The else
block of a guard
requires an exit path, either by using return
, throwing an exception or calling a @noreturn
. The easiest solution is to add a return statement.
func showKitten(kitten: Kitten?) {
guard let k = kitten else {
print("There is no kitten")
return
}
print(k)
}
Here's a version that throws an exception.
enum KittenError: Error {
case NoKitten
}
struct Kitten {
}
func showKitten(kitten: Kitten?) throws {
guard let k = kitten else {
print("There is no kitten")
throw KittenError.NoKitten
}
print(k)
}
try showKitten(kitten: nil)
Finally, here's an implementation calling fatalError()
, which is a @noreturn
function.
struct Kitten {
}
func showKitten(kitten: Kitten?) {
guard let k = kitten else {
print("There is no kitten")
fatalError()
}
print(k)
}
[/spoiler]
Advanced Verbal Questions
Question #1
Are closures value or reference types?
[spoiler title="Answer"]
Closures are reference types. If you assign a closure to a variable and you copy the variable into another variable, you also copy a reference to the same closure and its capture list.
[/spoiler]
Question #2
You use the UInt
type to store unsigned integers. It implements the following initializer to convert from a signed integer:
init(_ value: Int)
However, the following code generates a compile time error exception if you provide a negative value:
let myNegative = UInt(-1)
An unsigned integer by definition cannot be negative. However, it's possible to use the memory representation of a negative number to translate to an unsigned integer. How can you convert an Int
negative number into an UInt
while keeping its memory representation?
[spoiler title="Answer"]
There's an initializer for that:
UInt(bitPattern: Int)
making the implementation:
let myNegative = UInt(bitPattern: -1)
[/spoiler]
Question #3
Can you describe a circular reference in Swift? How can you solve it?
[spoiler title="Answer"]
A circular reference happens when two instances hold a strong reference to each other, causing a memory leak because neither of the two instances will ever be deallocated. The reason is that you cannot deallocate an instance as long as there's a strong reference to it, but each instance keeps the other alive because of its strong reference.
You'd solve the problem by breaking the strong circular reference by replacing one of the strong references with a weak
or an unowned
reference.
[/spoiler]
Question #4
Swift allows the creation of recursive enumerations. Here's an example of such an enumeration with a Node
case that takes two associated value types, T
and List
:
enum List<T> {
case node(T, List<T>)
}
This returns a compilation error. What is the missing keyword?
[spoiler title="Answer"]
It's the indirect
keyword that allows for recursive enumeration cases like this:
enum List<T> {
indirect case node(T, List<T>)
}
[/spoiler]
Where to Go From Here?
Congratulations on making it to the end of this Q&A, and don't feel bad if you didn't know all the answers!
Some of these questions are pretty complicated. Swift is a rich, expressive language and there's a lot to learn about it. Apple keeps improving — and changing — it so even the most experienced developers don't know everything.
To get to know Swift or build upon what you already know, be sure to check out Swift Apprentice.
The ultimate resource for all aspects of Swift is the official documentation, The Swift Programming Language, by Apple.
At the end of the day, using a language is the best way to learn it. Play with Swift in a playground or adopt it in a real project. Swift works (almost) seamlessly with Objective-C, so adding it to an existing project you already know is an excellent way to learn its ins and outs.
Thanks for visiting and working through these questions! Feel free to chime in below with your questions, problems and discoveries. I wouldn't mind if you wanted to pose some of your own challenges, too. See you in the forums!