![I KNOW iOS]()
Even though Swift is only a year old, it’s already one of the most popular languages. Its syntax looks very easy — so easy that when it was announced JavaScript developers felt like the image to the right.
In reality, Swift, is a complex language. It embraces both object oriented and functional approaches, and it’s still evolving with each new release.
There’s a lot to Swift – but how can you test how much you’ve learned? In this article, the raywenderlich.com Tutorial Team and I have put together a list of sample Swift interview questions.
You can use these questions to interview candidates to test their Swift knowledge, or test your own! And if you don’t know the answer, don’t worry: each question has a solution so you can learn.
The questions are split into two sections:
- Written questions: Good to include in a take-by-email programming test, since it sometimes involves writing a bit of code.
- Verbal questions: Good to ask over the phone or in a face-to-face interview, as they can be answered more easily verbally.
Also, each section is split into three levels:
- Beginner: Suitable for a beginner to Swift, who’s read a book or two on the subject and started working with Swift in their own apps.
- Intermediate: Suitable for someone who’s got a strong interest in language concepts, who has been reading a lot of blog posts about Swift and experimenting with it further.
- Advanced: Suitable for the best of the best only – folks who enjoy thoroughly exploring the language, challenging themselves, and using the cutting-edge techniques.
If you want to try answering these questions, I suggest you keep a Playground open to play with the code attached to the question before answering. Answers were tested against Xcode 7.0 beta 6.
Ready? Buckle up, it’s time to go!
Written Questions
Beginners
Hello there, padowan. I’ll start you off with the basics.
Question #1 – Swift 1.0 or later
What’s a better way to write this for
loop with ranges?
for var i = 0; i < 5; i++ {
print("Hello!")
} |
Solution Inside: Answer |
SelectShow> |
for i in 0...4 {
print("Hello!")
} |
Swift implements two range operators, the closed operator and the half-open operator. The first includes all the values in a range. For example, the following includes all the integers from 0 to 4:
The half open operator doesn’t include the last element. The following produces the same 0 to 4 result:
|
Question #2 – Swift 1.0 or later
Consider the following:
struct Tutorial {
var difficulty: Int = 1
}
var tutorial1 = Tutorial()
var tutorial2 = tutorial1
tutorial2.difficulty = 2 |
What’s the value of tutorial1.difficulty
and tutorial2.difficulty
? Would this be any different if Tutorial
was a class? Why?
Solution Inside: Answer |
SelectShow> |
tutorial1.difficulty is 1 , whereas tutorial2.difficulty is 2 .
Structures in Swift are value types, and they are copied by value rather than reference. The following line creates a copy of tutorial1 and assigns it to tutorial2 :
var tutorial2 = tutorial1 |
From this line on, any change to tutorial2 is not reflected in tutorial1 .
If Tutorial were a class, both tutorial1.difficulty and tutorial2.difficulty would be 2 . Classes in Swift are reference types. Any change to a property of tutorial1 would be reflected into tutorial2 and vice versa.
|
Question #3 – Swift 1.0 or later
view1
is declared with var
, and view2
is declared with let
. What’s the difference here, and will the last line compile?
import UIKit
var view1 = UIView()
view1.alpha = 0.5
let view2 = UIView()
view2.alpha = 0.5 // Will this line compile? |
Solution Inside: Answer |
SelectShow> |
view1 is a variable and can be re-assigned to a new instance of UIView . With let you can assign a value only once, so the following code doesn’t compile:
view2 = view1 // Error: view2 is immutable |
However, UIView is a class with reference semantics, so you can mutate the properties of view2 (which means the last line will compile):
let view2 = UIView()
view2.alpha = 0.5 // Yes! |
|
Question #4 – Swift 1.0 or later
This code sorts an array of names alphabetically and looks complicated. Simplify it and the closure as much as you can.
let animals = ["fish", "cat", "chicken", "dog"]
let sortedAnimals = animals.sort { (one: String, two: String) -> Bool in
return one < two
} |
Solution Inside: Answer |
SelectShow> |
The first simplification is related to the parameters. The type inference system can calculate the type of the parameters in the closure, so you can get rid of them:
let sortedAnimals = animals.sort { (one, two) -> Bool in return one < two } |
The return type can also be inferred, so drop it:
let sortedAnimals = animals.sort { (one, two) in return one < two } |
The $i notation can substitute the parameter names:
let sortedAnimals = animals.sort { return $0 < $1 } |
In single statement closures, the return keyword can be omitted. The return value of the last statement becomes the return value of the closure:
let sortedAnimals = animals.sort { $0 < $1 } |
This is simpler already, but don’t stop now!
For strings, there’s a comparison function defined as follows:
func <(lhs: String, rhs: String) -> Bool |
This neat little function makes your code as easy as:
let sortedAnimals = animals.sort(<) |
Notice that each step of this progression compiles and outputs the same result, and you made a one-character closure!
|
Question #5 – Swift 1.0 or later
This code creates two classes, Address
and Person
, and it creates two instances to represent Ray and Brian.
class Address {
var fullAddress: String
var city: String
init(fullAddress: String, city: String) {
self.fullAddress = fullAddress
self.city = city
}
}
class Person {
var name: String
var address: Address
init(name: String, address: Address) {
self.name = name
self.address = address
}
}
var headquarters = Address(fullAddress: "123 Tutorial Street", city: "Appletown")
var ray = Person(name: "Ray", address: headquarters)
var brian = Person(name: "Brian", address: headquarters) |
Suppose Brian moves to the new building across the street, so you update his record like this:
brian.address.fullAddress = "148 Tutorial Street" |
What’s going on here? What’s wrong with this?
![I know it]()
Solution Inside: Answer |
SelectShow> |
Ray also moved to the new building! Address is a class and has reference semantics, so headquarters is the same instance, whether you access it via ray or brian . Changing the address of headquarters will change it for both. Can you imagine what would happen if Brian got Ray’s mail or vice versa? :]
The solution is to create a new Address to assign to Brian, or to declare Address as a struct instead of a class.
|
Intermediate
Now to step up the difficulty and the trickiness. Are you ready?
Question #1 – Swift 2.0 or later
Consider the following:
var optional1: String? = nil
var optional2: String? = .None |
What’s the difference between nil
and .None
? How do the optional1
and optional2
variables differ?
Solution Inside: Answer |
SelectShow> |
There is no difference. Optional.None (.None for short) is the correct way of initializing an optional variable lacking a value, whereas nil is just syntactic sugar for .None .
In fact, this statement outputs true:
nil == .None // On Swift 1.x this doesn't compile. You need Optional<Int>.None |
Remember that under the hood an optional is an enumeration:
enum Optional<T> {
case None
case Some(T)
} |
|
Question #2 – Swift 1.0 or later
Here’s a model of a thermometer as a class and a struct:
public class ThermometerClass {
private(set) var temperature: Double = 0.0
public func registerTemperature(temperature: Double) {
self.temperature = temperature
}
}
let thermometerClass = ThermometerClass()
thermometerClass.registerTemperature(56.0)
public struct ThermometerStruct {
private(set) var temperature: Double = 0.0
public mutating func registerTemperature(temperature: Double) {
self.temperature = temperature
}
}
let thermometerStruct = ThermometerStruct()
thermometerStruct.registerTemperature(56.0) |
This code fails to compile. Where? Why?
Tip: Read it carefully and think about it a bit before testing it in a Playground.
Solution Inside: Answer |
SelectShow> |
The compiler will complain about the last line. The ThermometerStruct is correctly declared with a mutating function to change its internal variable temperature , but the compiler complains because the registerTemperature is invoked on an instance created via let , thus it’s immutable.
In structures, methods that change the internal state must be marked as mutating but invoking them from immutable variables is not allowed.
|
Question #3 – Swift 1.0 or later
What will this code print out and why?
var thing = "cars"
let closure = { [thing] in
print("I love \(thing)")
}
thing = "airplanes"
closure() |
Solution Inside: Answer |
SelectShow> |
It’ll print I love cars . The capture list creates a copy of thing when the closure is declared, so the captured value doesn’t change, even if you assign a new value to thing .
If you omit the capture list in the closure, then the compiler uses a reference instead of a copy. In this case, any change to the variable is reflected when the closure is invoked, as in the following code:
var thing = "cars"
let closure = {
print("I love \(thing)")
}
thing = "airplanes"
closure() // Prints "I love airplanes" |
|
Question #4 – Swift 2.0 or later
Here’s a global function that counts the number of unique values in an array:
func countUniques<T: Comparable>(array: Array<T>) -> Int {
let sorted = array.sort(<)
let initial: (T?, Int) = (.None, 0)
let reduced = sorted.reduce(initial) { ($1, $0.0 == $1 ? $0.1 : $0.1 + 1) }
return reduced.1
} |
It uses <
and ==
operators, so it restricts T
to types that implement, the Comparable
protocol.
You call it like this:
countUniques([1, 2, 3, 3]) // result is 3 |
Rewrite this function as an extension method on Array
so that you can write something like this:
[1, 2, 3, 3].countUniques() // should print 3 |
Solution Inside: Answer |
SelectShow> |
In Swift 2.0, generic types can be extended with conditions by enforcing type constraints. If the generic type doesn't satisfy the constraint, the extension is neither visible nor accessible.
So the global countUniques function can be rewritten as an Array extension:
extension Array where Element: Comparable {
func countUniques() -> Int {
let sorted = sort(<)
let initial: (Element?, Int) = (.None, 0)
let reduced = sorted.reduce(initial) { ($1, $0.0 == $1 ? $0.1 : $0.1 + 1) }
return reduced.1
}
} |
Notice that the new method is available only when the generic Element type implements the Comparable protocol. For example, the compiler will complain if you call it on an array of UIView s as follows:
import UIKit
let a = [UIView(), UIView()]
a.countUniques() // compiler error here because UIView doesn't implement Comparable |
|
Question #5 - Swift 2.0 or later
Here's a function to calculate divisions given to 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 == .None {
return .None
}
if divisor == .None {
return .None
}
if divisor == 0 {
return .None
}
return dividend! / divisor!
} |
This code works as expected but has two issues:
- The preconditions could take advantage of the
guard
statement
- It uses forced unwrapping
Improve this function using the guard
statement and avoid the usage of forced unwrapping.
Solution Inside: Answer |
SelectShow> |
The new guard statement introduced in Swift 2.0 provides an exit path if a condition is not met. It's very helpful to check preconditions, because it lets you express them in a clear way -- without the typical pyramid of doom of nested if statements. Here is an example:
guard dividend != .None else { return .None } |
It can also be used for optional binding, making the unwrapped variable accessible after the guard statement:
guard let dividend = dividend else { return .None } |
So the divide function can be rewritten as:
func divide(dividend: Double?, by divisor: Double?) -> Double? {
guard let dividend = dividend else { return .None }
guard let divisor = divisor else { return .None }
guard divisor != 0 else { return .None }
return dividend / divisor
} |
Notice the absence of the implicitly unwrapped operators on the last line, because both dividend and divisor have been unwrapped and stored in non-optional immutables.
One more thing. You can group guard statements, so you can make the function simpler:
func divide(dividend: Double?, by divisor: Double?) -> Double? {
guard let dividend = dividend, divisor = divisor where divisor != 0 else { return .None }
return dividend / divisor
} |
There are now only two guard statements, because you specify the non-zero condition using the where clause on the unwrapped variable divisor .
|
Oh, hi there. You're now at the midpoint and I see you're going strong. Shall we see how you fare with some advanced questions?
![Think you're clever, do you? This is when I step in.]()
Advanced
Question #1 - Swift 1.0 or later
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 obviously 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? Hint: it has to do with convertibles, but not convertibles like Camaros and Mustangs :)
Solution Inside: Answer |
SelectShow> |
Swift defines the following protocols that enable a type to be initialized with literal values by using the assignment operator:
NilLiteralConvertible
BooleanLiteralConvertible
IntegerLiteralConvertible
FloatLiteralConvertible
UnicodeScalarLiteralConvertible
ExtendedGraphemeClusterLiteralConvertible
StringLiteralConvertible
ArrayLiteralConvertible
DictionaryLiteralConvertible
Adopting the corresponding protocol and providing a public initializer allows literal initialization of a specific type. In the case of the Thermometer type, you implement the FloatLiteralConvertible protocol as follows:
extension Thermometer : FloatLiteralConvertible {
public init(floatLiteral value: FloatLiteralType) {
self.init(temperature: value)
}
} |
And now you can create an instance by using a simple float.
var thermometer: Thermometer = 56.8 |
|
Question #2 - Swift 1.0 or later
Swift has a set of predefined operators that perform different types of operations, such as arithmetic or logic. It also allows creating 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
- Ignores potential overflow errors
Solution Inside: Answer |
SelectShow> |
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.
In this case, the operator is ^^ and the type is infix (binary). Associativity is left , and precedence is set to 155 , given that multiplication and division have a value of 150. Here's the declaration:
infix operator ^^ { associativity left precedence 155 } |
The implementation is as follows:
import Foundation
func ^^(lhs: Int, rhs: Int) -> Int {
let l = Double(lhs)
let r = Double(rhs)
let p = pow(l, r)
return Int(p)
} |
Note that it doesn't take overflows into account; if the operation produces a result that Int can't represent, e.g. greater than Int.max , then a runtime error occurs.
|
Question #3 - Swift 1.0 or later
Can you define an enumeration with raw values like this? Why?
enum Edges : (Double, Double) {
case TopLeft = (0.0, 0.0)
case TopRight = (1.0, 0.0)
case BottomLeft = (0.0, 1.0)
case BottomRight = (1.0, 1.0)
} |
Solution Inside: Answer |
SelectShow> |
No, you cannot. A raw value type must:
- Conform to the
Equatable protocol
- Be literal convertible from any of the following types:
In the code above, the raw type is a tuple and is not compatible -- even if its individual values are.
|
Question #4 - Swift 2.0 or later
Consider the following code that defines Pizza
as a struct and Pizzeria
as a protocol, with an extension that includes a default implementation for the method 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() |
Solution Inside: Answer |
SelectShow> |
They both do. The Pizzeria protocol declares the makeMargherita() method and provides a default implementation. The method is overridden in the Lombardis implementation. Since the method is declared in the protocol in both cases, the correct implementation is invoked 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"])
}
} |
In this case, 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.
|
Question #5 - Swift 2.0 or later
The following code has a compile time error. Can you spot where and why it happens?
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 it.
Solution Inside: Answer |
SelectShow> |
The else body of any guard requires an exit path, either by using return , by throwing an exception or by 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: ErrorType {
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(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)
} |
|
Verbal Questions
![Yeah, that's right...I'm a Swift jedi]()
You're good, but you can't claim jedi status yet. Anybody can figure out the code, but how do you do with more open-ended questions of theory and practice?
To answer some of them you still might need to play with the code in a Playground.
Beginners
Question #1 - Swift 1.0 or later
What is an optional and what problem do optionals solve?
Solution Inside: Answer |
SelectShow> |
An optional is used to let a variable of any type represent the lack of value. In Objective-C, the absence of value is available in reference types only, and it uses the nil special value. Value types, such as int or float , do not have such ability.
Swift extends the lack of value concept to both reference and value types with optionals. An optional variable can hold either a value or nil any time.
|
Question #2 - Swift 1.0 or later
When should you use a structure, and when should you use a class?
Solution Inside: Answer |
SelectShow> |
There's an ongoing debate about whether using classes over structures is a good or bad practice. Functional programming tends to favor value types, whereas object-oriented programming prefers classes.
In Swift, classes and structures differ by a number of features. You can sum up the differences as follows:
- Classes support inheritance, structures don't
- Classes are reference types, structures are value types
There's no universal rule that determines what's best to use. The general recommendation is to use the most minimal tool required to accomplish your goal, but a good rule of thumb is to use structures unless you need inheritance or reference semantics.
For more details, check out this detailed post on the matter.
Note on performance: At runtime, structures are more performant than classes because method invocations are statically bound, whereas method invocation for classes is dynamically resolved at runtime. That's another good reason to use structures instead of classes when possible.
|
Question #3 - Swift 1.0 or later
What are generics and what problem do they solve?
Solution Inside: Answer |
SelectShow> |
Generics are used to make algorithms safely work with types. In Swift, generics can be used both in functions and data types, e.g. in classes, structures or enumerations.
Generics solve the problem of code duplication. A common case is when you have a method that takes a type of parameter and you have to duplicate it just to accommodate a parameter of another type.
For example, in the following code the second function is a "clone" of the first one -- it just accepts strings instead of integers.
func areIntEqual(x: Int, _ y: Int) -> Bool {
return x == y
}
func areStringsEqual(x: String, _ y: String) -> Bool {
return x == y
}
areStringsEqual("ray", "ray") // true
areIntEqual(1, 1) // true |
An Objective-C developer might think to resolve with an NSObject :
import Foundation
func areTheyEqual(x: NSObject, _ y: NSObject) -> Bool {
return x == y
}
areTheyEqual("ray", "ray") // true
areTheyEqual(1, 1) // true |
This code works as intended, but it's unsafe at compile time. It allows comparing a string with an integer, like this:
The application doesn't crash, but allowing the comparison of a string to an integer is probably not the intended result.
By adopting generics, you can conflate the two functions into one and keep type safety at the same time. Here's the implementation:
func areTheyEqual<T: Equatable>(x: T, _ y: T) -> Bool {
return x == y
}
areTheyEqual("ray", "ray")
areTheyEqual(1, 1) |
Since you're testing equality in this case, you restrict the parameters to any type that implements the Equatable protocol. This code achieves the intended result and prevents passing parameters of a different type.
![NOT BAD. Two birds, one stone.]()
|
Question #4 - Swift 1.0 or later
There are a few cases when you can't avoid using implicitly unwrapped optionals. When? Why?
Solution Inside: Answer |
SelectShow> |
The most common reasons to use implicitly unwrapped optionals are:
- When a property that is not
nil by nature cannot be initialized at instantiation time. A typical example is an Interface Builder outlet, which always initializes after its owner has been initialized. In this specific case -- assuming it's properly configured in Interface Builder -- the outlet is guaranteed to be non-nil before it's used.
- To solve the strong reference cycle problem, which is when two instances refer to each other and require a non-nil reference to the other instance. In such a case, one side of the reference can be marked
unowned , while the other uses an implicitly unwrapped optional.
Pro tip: Don't use implicitly unwrapped optionals unless you must. Using them improperly increases the chance of runtime crashes. In some cases, a crash might be the intended behavior, but there are better ways to achieve the same result, for example, by using fatalError() .
|
Question #5 - Swift 1.0 or later
What are the various ways to unwrap an optional? How do they rate in terms of safety?
Hint: There are six ways.
Solution Inside: Answer |
SelectShow> |
- forced unwrapping
! operator -- unsafe
- implicitly unwrapped variable declaration -- unsafe in many cases
- optional binding -- safe
- new Swift 2.0
guard statement -- safe
- optional chaining -- safe
- nil coalescing operator -- safe
|
![cant believe]()
Intermediate
Time to rachet up the challenge here. Seems you're doing just fine so far, but let's see if you make it through these questions.
Question #1 - Swift 1.0 or later
Is Swift an object-oriented language or a functional language?
Solution Inside: Answer |
SelectShow> |
Swift is a hybrid language that supports both paradigms.
It implements the three fundamental principles of OOP:
- Encapsulation
- Inheritance
- Polymorphism
As for Swift being a functional language, there are different but equivalent ways to define it.
One of the more common is on Wikipedia: "…a programming paradigm [...] that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data."
It's hard to argue that Swift is a full-fledged functional language, but it has the basics.
|
Question #2 - Swift 1.0 or later
Which of the following features are included in Swift?
- Generic classes
- Generic structs
- Generic protocols
Solution Inside: Answer |
SelectShow> |
- 1 and 2 are included. Generics can be used in classes, structs, enumerations, global functions and methods.
- 3 is partially implemented via
typealias . It's not a generic type per se, it's a placeholder name. It's often referred to as an associated type and it's defined when a protocol is adopted by a type.
|
Question #3 - Swift 1.0 or later
In Objective-C, a constant can be declared like this:
Here is the Swift counterpart:
Is there any difference between them? If yes, can you explain how they differ?
Solution Inside: Answer |
SelectShow> |
A const is a variable initialized with a compile time value or an expression resolved at compilation time.
An immutable created via let is a constant determined at runtime, and it can be initialized with the result being either a static or dynamic expression. Notice that its value can only be assigned once.
|
Question #4 - Swift 1.0 or later
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 reality they're different. Can you explain how they differ?
Solution Inside: Answer |
SelectShow> |
static makes a property or a function static and not overrideable. By using class , you can 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()
}
override static func illuminate() { // error: class method overrides a 'final' class method
super.illuminate()
}
} |
|
Question #5 - Swift 1.0 or later
Can you add a stored property by using an extension? Explain.
Solution Inside: Answer |
SelectShow> |
No, it's not possible. An extension can be used to add new behavior to an existing type, but not to alter 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.
|
Advanced
Oh boy, you're a clever one, aren't you? It's time to step it up another notch.
Question #1 - Swift 1.2
In Swift 1.2, can you explain the problem with declaring an enumeration with generic types? Take for example an Either
enumeration with two generic types T
and V
, with T
used as the associated value type for a Left
case and V
for a Right
case:
enum Either<T, V> {
case Left(T)
case Right(V)
} |
Pro tip: Inspect this case in an Xcode project, not in a Playground. Also notice that this question is related to Swift 1.2 so you'll need Xcode 6.4.
Solution Inside: Answer |
SelectShow> |
Compilation fails with the following (cryptic) error message:
unimplemented IR generation feature non-fixed multi-payload enum layout |
The problem is that the memory size of T cannot be determined upfront because it depends on the T type itself, but enum cases require a fixed-sized payload.
The most used workaround is to box the generic type into a reference type, conventionally called Box , as follows:
class Box<T> {
let value: T
init(_ value: T) {
self.value = value
}
}
enum Either<T, V> {
case Left(Box<T>)
case Right(Box<V>)
} |
This problem affects only Swift 1.0 or later, but it has been solved in 2.0.
|
Question #2 - Swift 1.0 or later
Are closures value or reference types?
Solution Inside: Answer |
SelectShow> |
Closures are reference types. If a closure is assigned to a variable and the variable is copied into another variable, a reference to the same closure and its capture list is also copied.
|
Question #3 - Swift 1.0 or later
The UInt
type is used to store unsigned integers. It implements the following initializer for converting from a signed integer:
However, the following code generates a compile time error exception if you provide a negative value:
let myNegative = UInt(-1) |
Knowing that a negative number is internally represented, using two's complement as a positive number, how can you convert an Int
negative number into an UInt
while keeping its memory representation?
Solution Inside: Answer |
SelectShow> |
There's an initializer for that:
|
Question #4 - Swift 1.0 or later
Can you describe a situation where you might get a circular reference in Swift, and how you'd solve it?
Solution Inside: Answer |
SelectShow> |
A circular reference happens when two instances hold a strong reference to each other, causing a memory leak because none of two instances will ever be deallocated. The reason is that an instance cannot be deallocated 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.
|
Question #5 - Swift 2.0 or later
Swift 2.0 features a new keyword to make recursive enumerations. Here is 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>)
} |
What's that keyword?
Solution Inside: Answer |
SelectShow> |
It's the indirect keyword that allows for recursive enumeration cases like this:
enum List<T> {
indirect case Cons(T, List<T>)
} |
|
Where To Go From Here?
Congrats on making it to the end, and don't feel bad if you didn't actually know all the answers!
Some of these questions are pretty complicated and Swift is a rich, expressive language. There's a lot to learn. Moreover, Apple keeps improving it with new features, so even the best of us may not know it all.
To get to know Swift or build upon what you already know, be sure to check out our in-depth, tutorial-rich book, Swift by Tutorials, or sign up for our hands-on tutorial conference RWDevCon!
Of course, the ultimate resource for all aspects of Swift is the official The Swift Programming Language by Apple.
At the end of the day, using a language is the best way to learn it. Just play with it in a Playground or adopt it in a real project. Swift works (almost) seamlessly with Objective-C, so building on an existing project you already know is an excellent way to learn the 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. We can all learn from each other. See you in the forums!
The post Swift Interview Questions and Answers appeared first on Ray Wenderlich.