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 #5
Here's a function to divide two optional doubles. There are three preconditions to verify before performing the actual division:
- The dividend must contain a non
nil
value. - The divisor must contain a non
nil
value. - The divisor must not be zero.
func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
if dividend == nil {
return nil
}
if divisor == nil {
return nil
}
if divisor == 0 {
return nil
}
return dividend! / divisor!
}
Improve this function by using the guard
statement and without using forced unwrapping.
[spoiler title="Answer"]
The guard
statement introduced in Swift 2.0 provides an exit path when a condition is not met. It's very helpful when checking preconditions because it lets you express them in a clear way — without the pyramid of doom of nested if
statements. Here is an example:
guard dividend != nil else { return nil }
You can also use the guard
statement for optional binding, which makes the unwrapped variable accessible after the guard
statement:
guard let dividend = dividend else { return .none }
So you can rewrite the divide
function as:
func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
guard let dividend = dividend else { return nil }
guard let divisor = divisor else { return nil }
guard divisor != 0 else { return nil }
return dividend / divisor
}
Notice the absence of the implicitly unwrapped operators on the last line because you've unwrapped both dividend
and divisor
and stored them in non-optional immutable variables.
Note that the results of the unwrapped optionals in a guard
statement are available for the rest of the code block that the statement appears in.
You can can simplify this further by grouping the guard
statements:
func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
guard
let dividend = dividend,
let divisor = divisor,
divisor != 0
else {
return nil
}
return dividend / divisor
}
[/spoiler]
Question #6
Rewrite the method from question five using an if let
statement.
[spoiler title="Answer"]
The if let
statement lets you unwrap optionals and use the value within that code block. Note that you cannot access the unwrapped optional outside the block. You can write the function using an if let
statement such as:
func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
if
let dividend = dividend,
let divisor = divisor,
divisor != 0 {
return dividend / divisor
} else {
return nil
}
}
[/spoiler]
Intermediate Verbal Questions
Question #1
In Objective-C, you declare a constant like this:
const int number = 0;
Here is the Swift counterpart:
let number = 0
What are the differences between them?
[spoiler title="Answer"]
A const
is a variable initialized at compile time with a value or an expression that must be resolved at compilation time.
An immutable created with let
is a constant determined at runtime. You can initialize it with a static or a dynamic expression. This allows a declaration such as:
let higherNumber = number + 5
Note that you can only assign its value once.
[/spoiler]
Question #2
To declare a static property or function, you use the static
modifier on value types. Here's an example for a structure:
struct Sun {
static func illuminate() {}
}
For classes, it's possible to use either the static
or the class
modifier. They achieve the same goal, but in different ways. Can you explain how they differ?
[spoiler title="Answer"]
static
makes a property or a function static and not overridable. Using class
lets you override the property or function.
When applied to classes, static
becomes an alias for class final
.
For example, in this code the compiler will complain when you try to override illuminate()
:
class Star {
class func spin() {}
static func illuminate() {}
}
class Sun : Star {
override class func spin() {
super.spin()
}
// error: class method overrides a 'final' class method
override static func illuminate() {
super.illuminate()
}
}
[/spoiler]
Question #3
Can you add a stored property to a type by using an extension? How or why not?
[spoiler title="Answer"]
No, it's not possible. You can use an extension to add new behavior to an existing type, but not to alter either the type itself or its interface. If you add a stored property, you'd need extra memory to store the new value. An extension cannot manage such a task.
[/spoiler]
Question #4
What is a protocol in Swift?
[spoiler title="Answer"]
A protocol is a type that defines a blueprint of methods, properties and other requirements. A class, structure or enumeration can then adopt the protocol to implement those requirements.
A type that adopts the requirements of a protocol conforms to that protocol. The protocol doesn't implement any functionality itself, but rather defines the functionality. You can extend a protocol to provide a default implementation of some of the requirements or additional functionality that conforming types can take advantage of.
[/spoiler]
Advanced Written Questions
Question #1
Consider the following structure that models a thermometer:
public struct Thermometer {
public var temperature: Double
public init(temperature: Double) {
self.temperature = temperature
}
}
To create an instance, you can use this code:
var t: Thermometer = Thermometer(temperature:56.8)
But it would be nicer to initialize it this way:
var thermometer: Thermometer = 56.8
Can you? How?
[spoiler title="Answer"]
Swift defines protocols that enable you to initialize a type with literal values by using the assignment operator. Adopting the corresponding protocol and providing a public initializer allows literal initialization of a specific type. In the case of Thermometer
, you implement ExpressibleByFloatLiteral
as follows:
extension Thermometer: ExpressibleByFloatLiteral {
public init(floatLiteral value: FloatLiteralType) {
self.init(temperature: value)
}
}
Now, you can create an instance by using a float.
var thermometer: Thermometer = 56.8
[/spoiler]
Question #2
Swift has a set of pre-defined operators to perform arithmetic or logic operations. It also allows the creation of custom operators, either unary or binary.
Define and implement a custom ^^ power operator with the following specifications:
- Takes two
Int
s as parameters. - Returns the first parameter raised to the power of the second.
- Correctly evaluates the equation using the standard algebraic order of operations.
- Ignores the potential for overflow errors.
[spoiler title="Answer"]
You create a new custom operator in two steps: Declaration and implementation.
The declaration uses the operator
keyword to specify the type (unary or binary), the sequence of characters composing the operator, its associativity and precedence. Swift 3.0 changed the implementation of precedence to use a precedence group.
Here, the operator is ^^ and the type is infix
(binary). Associativity is right
; in other words, equal precedence ^^ operators should evaluate the equation from right to left.
There is no predefined standard precedence for exponential operations in Swift. In the standard order of operations for algebra, exponents should calculate before multiplication/division. So you'll need to create a custom precedence that places them higher than multiplication.
Here's the declaration:
precedencegroup ExponentPrecedence {
higherThan: MultiplicationPrecedence
associativity: right
}
infix operator ^^: ExponentPrecedence
The implementation follows:
func ^^(base: Int, exponent: Int) -> Int {
let l = Double(base)
let r = Double(exponent)
let p = pow(l, r)
return Int(p)
}
Note that since the code doesn't take overflows into account, if the operation produces a result that Int
can't represent, such as a value greater than Int.max
, then a runtime error occurs.
[/spoiler]