Interview Questions Flashcards

1
Q

What is the difference between Upcast and Downcast in Swift?

A
  • The upcast, going from a derived class to a base class, can be checked at compile time and will never fail.
  • However, downcasts can fail since you can’t always be sure about the specific class. If you have a UIView, it’s possible it’s a UITableView or maybe a UIButton.
    • downcasts must be either optional with as? or
    • “forced failable” with as! when sure about the type
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What’s the difference between == and ===?

A
== operator checks if the values are the same, comparing value types. "equal to"
=== operator checks if the references point the same instance (both point to the same memory address), comparing reference types. "identical to"
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

How to append one array to another array in Swift?

Consider:
var first = [“John”, “Paul”]
let second = [“George”, “Ringo”]
How to append one array to another array in Swift? Note: the first array mutable so we can join the second array to it.

A

One option for joining arrays is the append(contentsOf:) method, used like this:

first.append(contentsOf: second)
Another option is using the += operator, which is overloaded for arrays to combine elements:

first += second
The third option is to use a regular + to create a new array by combining two others:

let third = first + second
All three options produce the same resulting array.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

How to break out of multiple loop levels?

Consider:

let numbers = 1…100

for number1 in numbers {
for number2 in numbers {
if number1 == number2 && number1 * number2 == 144 {
print(“Square found: (number1)”)
}
}
}
How to exit both loops as soon as the correct number 144 is found?

A

outerLoop: for number1 in numbers {
for number2 in numbers {
if number1 == number2 && number1 * number2 == 144 {
print(“Square found: (number1)”)
break outerLoop
}
}
}
Notice the outerLoop: before the for number1 loop, and also the matching break outerLoop – that will cause both loops to exit as soon as the correct number is found.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Rewrite this code in a Swift way

Consider:

let list = [Int](1...5)
var arrayOfTuples = [(Int, Int)]()

for (index, element) in list.enumerated() {
arrayOfTuples += [(index, element)]
}

print(arrayOfTuples) // prints [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
Can you rewrite this code in a more “swiftier” way?

A

Yeap, the way to do it is:

let list = [Int](1...5)
let arrayOfTuples = Array(list.enumerated())
print(arrayOfTuples) // prints [(offset: 0, element: 1), (offset: 1, element: 2), (offset: 2, element: 3), (offset: 3, element: 4), (offset: 4, element: 5)]
or with map:
let list = [Int](1...5)
let arrayOfDictionaries = list.enumerated().map { (a, b) in return [a : b] }
print(arrayOfDictionaries) // prints [[0: 1], [1: 2], [2: 3], [3: 4], [4: 5]]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What Classes and Structs have in common in Swift and what are their differences?

A

Answer
The features classes and structs have in common:

  • Both structs and classes can define properties to store values, and they can define functions
  • They can define subscripts to provide access to values with subscript syntax
  • They can define initializers to set up their initial state, with init()
  • They can be extended with extension (this is important!)
  • They can conform to protocols, for example to support Protocol Oriented Programming
  • They can work with generics to provide flexible and reusable types
    Classes support a few more capabilities that structs don’t have:
  • Classes can inherit from another class, like you inherit from UIViewController to create your own view controller subclass
  • Classes can be deinitialized, i.e. you can invoke a deinit() function before the class is destroyed
  • Classes are reference types and structs are value types
    • Value Type: When you copy a value type (i.e., when it’s assigned, initialized or passed into a function), each instance keeps a unique copy of the data. If you change one instance, the other doesn’t change too.
    • Reference Type: When you copy a reference type, each instance shares the data. The reference itself is copied, but not the data it references. When you change one, the other changes too.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What does the Swift mutating keyword mean?

A

Being the value type structs are immutable. Meaning other variables can not change the values for instance of structure at any given point.

The mutating word is required for changing the values of self variables inside structure’s function only.

For. e.g

struct MyStruct {
var abc: String = “initila value”

    func changeValue() {
        abc = "some other value". //Compile time error: Cannot assign to property: 'self' is immutable. Mark method 'mutating' to make 'self' mutable.
    }
}
Here as we are trying to change value of variable abc inside function declared in struct itself, we get the compile time error.

So here we need to make function mutating to make change value inside structure. Hence the correct code will be:

struct MyStruct {
var abc: String = “initila value”

mutating func changeValue() {
    abc = "some other value"    } }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What is trailing closure syntax?

A

Many functions in iOS accept multiple parameters where the final parameter is a closure. Trailing closure syntax is a little piece of syntactic sugar that makes particularly common code more pleasant to read and write.

Consider:

func greetThenRunClosure(name: String, closure: () -> ()) {
    print("Hello, \(name)!")
    closure()
}
Use:

greetThenRunClosure(name: “Paul”) {
print(“The closure was run”)
}
This functionality is available wherever a closure is the final parameter to a function.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

What is a good use case for an inout parameter?

A

Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error.

inout means that modifying the local variable will also modify the passed-in parameters. Without it, the passed-in parameters will remain the same value. Trying to think of reference type when you are using inout and value type without using it.

A good use case will be swap function that it will modify the passed-in parameters.
Consider removing the overhead of copying as well. If you have a function that takes a somewhat memory-wise large value type as argument (say, a large structure type) and that returns the same type, and finally where the function return is always used just to replace the caller argument, then inout is to prefer as associated function parameter.
struct MyStruct {
private var myInt: Int = 1

// ... lots and lots of stored properties

mutating func increaseMyInt() {
    myInt += 1
} }
/* call to function _copies_ argument to function property 'myHugeStruct' (copy 1)
   function property is mutated
   function returns a copy of mutated property to caller (copy 2) */
func myFunc(var myHugeStruct: MyStruct) -> MyStruct {
    myHugeStruct.increaseMyInt()
    return myHugeStruct
}
/* call-by-reference, no value copy overhead due to inout opimization */
func myFuncWithLessCopyOverhead(inout myHugeStruct: MyStruct) {
    myHugeStruct.increaseMyInt()
}
var a = MyStruct()
a = myFunc(a) // copy, copy: overhead
myFuncWithLessCopyOverhead(&a) // call by reference: no memory reallocation
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What is difference between as?, as! and as in Swift?

A
In Swift 1.2 and later, as can only be used for upcasting (or disambiguation) and pattern matching:
// 'as' for pattern matching
switch item {
case let obj as MyObject:
    // this code will be executed if item is of type MyObject
case let other as SomethingElse:
    // this code will be executed if item is of type SomethingElse
...
}
 - as? produces an optional value, which is either the value if it can be cast to the specified type, or nil if it can't.
- as! doesn't produce an optional, it just produces a value of the specified type, and if the cast fails, it aborts the program. Saying foo as! SomeType is basically the same thing as saying (foo as? SomeType)! (except you get a better error message).
You should only ever use as! if you're 100% certain the cast will succeed (because if you're wrong, the whole program aborts).
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What’s the difference between Self vs self?

A

When you’re writing protocols and protocol extensions, there’s a difference between Self (capital S) and self (lowercase S). When used with a capital S, Self refers to the type that conform to the protocol, e.g. String or Int. When used with a lowercase S, self refers to the value inside that type, e.g. “hello” or 556.

As an example, consider this extension on BinaryInteger:

extension BinaryInteger {
    func squared() -> Self {
        return self * self
    }
}
Remember, Self with a capital S refers to whatever type is conforming to the protocol. In the example above, Int conforms to BinaryInteger, so when called on Int the method returns an Int.

On the other hand, self with a lowercase S refers to whatever value the type holds. If the example above were called on an Int storing the value 5 it would effectively be 5 * 5.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What’s the difference between a protocol and a class in Swift?

A

In their basic form, a protocol describes what an unknown type of object can do. You might say it has two or three properties of various types, plus methods. But that protocol never includes anything inside the methods, or provides actual storage for the properties.

In a more advanced form, you can write extensions on your protocols that provide default implementations of the methods. You still can’t provide storage for properties, however.

In comparison, classes are concrete things. While they might adopt protocols – i.e., say they implement the required properties and methods – they aren’t required to do that. You can create objects from classes, whereas protocols are just type definitions. Try to think of protocols as being abstract definitions, whereas classes and structs are real things you can create.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

When to use strong, weak and unowned references?

A
  • To determine if you even need to worry about strong, weak, or unowned, ask, “Am I dealing with reference types”. If you’re working with Structs or Enums, ARC isn’t managing the memory for those Types and you don’t even need to worry about specifying weak or unowned for those constants or variables.
  • Strong references are fine in hierarchical relationships where the parent references the child, but not vice-versa. In fact, strong references are the most appropraite kind of reference most of the time.
  • When two instances are optionally related to one another, make sure that one of those instances holds a weak reference to the other.
  • When two instances are related in such a way that one of the instances can’t exist without the other, the instance with the mandatory dependency needs to hold an unowned reference to the other instance.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

When to use a set rather than an array in Swift?

A

You should use a set rather than an array if all the following criteria are true:

  1. You intend to add each item only once. Sets never allow duplicates.
  2. You don’t care about the order of the items in the set.
  3. You don’t need to use APIs that require arrays.
  4. You’re storing Hashable types, either your own or one of Swift’s built-in types likes strings and integers. Sets use hash values for fast look up of items.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

When would you use self in a method?

A

By far the most common reason for using self is inside an initializer, where your likely to want parameter names that match the property names of your type, like this:

struct Student {
var name: String
var bestFriend: String

init(name: String, bestFriend: String) {
    print("Enrolling \(name) in class…")
    self.name = name
    self.bestFriend = bestFriend
} }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Can you rewrite this code using mutating function?

Consider:

struct Counter {
let count: Int

init(count: Int = 0) {
    self.count = count
}
    // the functional approach
    func counterByIncrementing() -> Counter {
        let newCount = count + 1
        return Counter(count: newCount)
    }
}
var counter = Counter()
counter = counter.counterByIncrementing()
Can you rewrite this code using mutating function?
A

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

However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends. The method can also assign a completely new instance to its implicit self property, and this new instance will replace the existing one when the method ends.

You can opt in to this behavior by placing the mutating keyword before the func keyword for that method.

Consider:

struct Counter {
    // this now has to be a var :/
    var count: Int
init(count: Int = 0) {
    self.count = count
}
    // the mutating keyword approach
    mutating func increment() {
        count += 1
    }
}
var counter = Counter()
counter.increment()
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Explain when to use different Swift casting operators?

A

The as operator

The as operator performs a cast when it is known at compile time that the cast always succeeds, such as upcasting or bridging. Upcasting lets you use an expression as an instance of its type’s supertype, without using an intermediate variable.
This is the most preferable operator to use, when possible. It guarentees success, without worrying about unwrapping an optional or risking a crash.
The as? operator

The as? operator performs a conditional cast of the expression to the specified type. The as? operator returns an optional of the specified type. At runtime, if the cast succeeds, the value of expression is wrapped in an optional and returned; otherwise, the value returned is nil. If casting to the specified type is guaranteed to fail or is guaranteed to succeed, a compile-time error is raised.
This is the second most preferable operator to use. Use it to safely handle the case in which a casting operator can’t be performed.
The as! operator

The as! operator performs a forced cast of the expression to the specified type. The as! operator returns a value of the specified type, not an optional type. If the cast fails, a runtime error is raised. The behavior of x as! T is the same as the behavior of (x as? T)!.
This is the least preferable operator to use. I strongly advise against abusing it. Attempting to cast an expression to an incompatible type crashes your program.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Explain the difference between weak and unowned references. Provide an example.

A

Both weak and unowned references do not create a strong hold on the referred object (a.k.a. they don’t increase the retain count in order to prevent ARC from deallocating the referred object).

A weak reference allows the possibility of it to become nil (this happens automatically when the referenced object is deallocated), therefore the type of your property must be optional - so you, as a programmer, are obligated to check it before you use it (basically the compiler forces you, as much as it can, to write safe code). Used for scenarios when _both entities can exis_t without having a strict dependency upon the other.

class Person {
   let name: String
   init(name: String) { self.name = name }
   var apartment: Apartment?
}
class Apartment {
   let number: Int
   init(number: Int) { self.number = number }
   weak var tenant: Person?
}
or

Person ===(strong)==> Apartment
Person <==(weak)===== Apartment
The Person and Apartment example shows a situation where two properties, both of which are allowed to be nil, have the potential to cause a strong reference cycle and can exist without having a strict dependency upon the other.

An unowned reference presumes that it will never become nil during its lifetime. An unowned reference must be set during initialization - this means that the reference will be defined as a non-optional type that can be used safely without checks. If somehow the object being referred to is deallocated, then the app will crash when the unowned reference is used.

class Customer {
let name: String
var card: CreditCard?
init(name: String) { self.name = name }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer }
}
In this example, a Customer may or may not have a CreditCard, but a CreditCard will always be associated with a Customer.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Is there a way to create an abstract class in Swift?

A

here are no abstract classes in Swift. You can achieve the same behaviour as abstract class with protocols and protocol extensions.

First, you write a protocol that acts as an interface for all the methods that have to be implemented in all types that conform to it.

protocol Drivable {
var speed: Float { get set }
}
Then you can add default behaviour to all types that conform to it

extension Drivable {
    func accelerate(by: Float) {
        speed += by
    }
}
You can now create new types by implementing Drivable.

struct Car: Drivable {
var speed: Float = 0.0
init() {}
}

let c = Car()
c.accelerate(10)
So basically you get:

Compile time checks that guarantee that all Drivables implement speed
You can implement default-behaviour for all types that conform to Drivable (accelerate)
Drivable is guaranteed not to be instantiated since it’s just a protocol

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

What is Copy on Write (Cow) in Swift?

A

Copy on Write (CoW or COW), sometimes referred to as implicit sharing or shadowing is a resource-management technique used in computer programming to efficiently implement a “duplicate” or “copy” operation on modifiable resources. If a resource duplicated but not modified it is not necessary to create a new resource. The resource can be shared between the copy and the original.

At a basic level, Array is just a structure that holds a reference to a heap-allocated buffer containing the elements – therefore multiple Array instances can reference the same buffer. When you come to mutate a given array instance, the implementation will check if the buffer is uniquely referenced, and if so, mutate it directly. Otherwise, the array will perform a copy of the underlying buffer in order to preserve value semantics.

Copy on write is a feature specifically added to Swift arrays and dictionaries; you don’t get it for free in your own data types.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

What is the difference between fileprivate and private?

A

fileprivate can be accessed from the their entire files. Restricts the use of an entity to its defining source file.

private can only be accessed from their single declaration and to extensions of that declaration that are in the same file; For instance:

// Declaring "A" class that has the two types of "private" and "fileprivate":
class A {
    private var aPrivate: String?
    fileprivate var aFileprivate: String?
    func accessMySelf() {
        // this works fine
        self.aPrivate = ""
        self.aFileprivate = ""
    }
}
// Declaring "B" for checking the abiltiy of accessing "A" class:
class B {
    func accessA() {
        // create an instance of "A" class
        let aObject = A()
        // Error! this is NOT accessable...
        aObject.aPrivate = "I CANNOT set a value for it!"
        // this works fine
        aObject.aFileprivate = "I CAN set a value for it!"
    }
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

What is the difference between open and public keywords in Swift?

A

In short:

An open class is accessible and subclassable outside of the defining module. An open class member is accessible and overridable outside of the defining module. The reasoning there is some classes of libraries and frameworks are not designed to be subclassed and doing so may result in unexpected behavior.
A public class is accessible but not subclassable outside of the defining module. A public class member is accessible but not overridable outside of the defining module.
// First.framework – A.swift
open class A {}
// First.framework – B.swift
public class B: A {} // ok
// Second.framework – C.swift

import First

internal class C: A {} // ok
// Second.framework – D.swift

import First

internal class D: B {} // error: B cannot be subclassed

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

What to use: [String: Any] or [String: AnyObject]?

A

Whether you use Any or AnyObject depends on your intended use:

If your dictionary will be used only within Swift code, then you should use Any because your types (Int, Double, Float, String, Array, and Dictionary) are not objects.

If you will be passing your dictionary to Objective-C routines that expect an NSDictionary, then you should use AnyObject.

When you import Foundation or import UIKit or import Cocoa, it is possible to declare your array as [String: AnyObject], but in this case Swift is treating your Int, Double, Float literals as NSNumber, your Strings as NSString, your Arrays as NSArray, and your dictionaries as NSDictionary, all of which are objects. A dictionary using AnyObject as the value type is convertible to NSDictionary, but one using Any is not.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

What’s wrong with this code?

You see this code on a code review:

self.self.someProperty
What’s wrong with it? Will it compile?

A

Nothing wrong with this code except it may be more succinct. The .self property of an object is that object itself. So your second self changes nothing.

You could, in fact, extend this game indefinitely (or as long as your patience holds out):

let s = "Hello".self.self.self.self.self.self.self.self
// s is still simply "Hello"
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

What’s the difference between Any and AnyObject?

A

Swift provides two special types for working with nonspecific types:

Any can represent an instance of any type at all (both value and reference types), including function types.
AnyObject can represent an instance of any class type (reference types).
Use Any and AnyObject only when you explicitly need the behavior and capabilities they provide. It is always better to be specific about the types you expect to work with in your code.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q

What is the use of Hashable protocol?

A
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q

What’s the difference between init?() and init()?

A
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q

What is the difference between fileprivate and private?

A

fileprivate can be accessed from the their entire files. Restricts the use of an entity to its defining source file.

private can only be accessed from their single declaration and to extensions of that declaration that are in the same file; For instance:

// Declaring "A" class that has the two types of "private" and "fileprivate":
class A {
    private var aPrivate: String?
    fileprivate var aFileprivate: String?
    func accessMySelf() {
        // this works fine
        self.aPrivate = ""
        self.aFileprivate = ""
    }
}
// Declaring "B" for checking the abiltiy of accessing "A" class:
class B {
    func accessA() {
        // create an instance of "A" class
        let aObject = A()
        // Error! this is NOT accessable...
        aObject.aPrivate = "I CANNOT set a value for it!"
        // this works fine
        aObject.aFileprivate = "I CAN set a value for it!"
    }
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q

What is Copy on Write (Cow) in Swift?

A

Copy on Write (CoW or COW), sometimes referred to as implicit sharing or shadowing is a resource-management technique used in computer programming to efficiently implement a “duplicate” or “copy” operation on modifiable resources. If a resource duplicated but not modified it is not necessary to create a new resource. The resource can be shared between the copy and the original.

At a basic level, Array is just a structure that holds a reference to a heap-allocated buffer containing the elements – therefore multiple Array instances can reference the same buffer. When you come to mutate a given array instance, the implementation will check if the buffer is uniquely referenced, and if so, mutate it directly. Otherwise, the array will perform a copy of the underlying buffer in order to preserve value semantics.

Copy on write is a feature specifically added to Swift arrays and dictionaries; you don’t get it for free in your own data types.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q

Can you rewrite this code using mutating function?

Consider:

struct Counter {
let count: Int

init(count: Int = 0) {
    self.count = count
}
    // the functional approach
    func counterByIncrementing() -> Counter {
        let newCount = count + 1
        return Counter(count: newCount)
    }
}
var counter = Counter()
counter = counter.counterByIncrementing()
Can you rewrite this code using mutating function?
A

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

However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends. The method can also assign a completely new instance to its implicit self property, and this new instance will replace the existing one when the method ends.

You can opt in to this behavior by placing the mutating keyword before the func keyword for that method.

Consider:

struct Counter {
    // this now has to be a var :/
    var count: Int
init(count: Int = 0) {
    self.count = count
}
    // the mutating keyword approach
    mutating func increment() {
        count += 1
    }
}
var counter = Counter()
counter.increment()
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q

When would you use self in a method?

A

By far the most common reason for using self is inside an initializer, where your likely to want parameter names that match the property names of your type, like this:

struct Student {
var name: String
var bestFriend: String

init(name: String, bestFriend: String) {
    print("Enrolling \(name) in class…")
    self.name = name
    self.bestFriend = bestFriend
} }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
32
Q

What is trailing closure syntax?

A

Many functions in iOS accept multiple parameters where the final parameter is a closure. Trailing closure syntax is a little piece of syntactic sugar that makes particularly common code more pleasant to read and write.

Consider:

func greetThenRunClosure(name: String, closure: () -> ()) {
    print("Hello, \(name)!")
    closure()
}
Use:

greetThenRunClosure(name: “Paul”) {
print(“The closure was run”)
}
This functionality is available wherever a closure is the final parameter to a function.

33
Q

How to break out of multiple loop levels?

Consider:

let numbers = 1…100

for number1 in numbers {
for number2 in numbers {
if number1 == number2 && number1 * number2 == 144 {
print(“Square found: (number1)”)
}
}
}
How to exit both loops as soon as the correct number 144 is found?

A

Consider:

outerLoop: for number1 in numbers {
for number2 in numbers {
if number1 == number2 && number1 * number2 == 144 {
print(“Square found: (number1)”)
break outerLoop
}
}
}
Notice the outerLoop: before the for number1 loop, and also the matching break outerLoop – that will cause both loops to exit as soon as the correct number is found.

34
Q

What is CoreData?

A

Core Data is an object graph management framework. It manages a potentially very large graph of object instances, allowing an app to work with a graph that would not entirely fit into memory by faulting objects in and out of memory as necessary. Core Data also manages constraints on properties and relationships and maintains reference integrity (e.g. keeping forward and backward links consistent when objects are added/removed to/from a relationship). Core Data is thus an ideal framework for building the “model” component of an MVC architecture.

To implement its graph management, Core Data happens to use SQLite as a disk store. It could have been implemented using a different relational database or even a non-relational database such as CouchDB. Core Data isn’t so much a database engine as it is an API that abstracts over the actual data store. You can tell Core Data to save as an sqlite database, a plist, a binary file, or even a custom data store type.

35
Q

Explain what is NSUserDefaults?

A

NSUserDefaults is the easiest way to store data without a database using key-value pair. This approach is the ideal way to store small amounts of data. In most cases, NSUserDefaults is best used to save user’s settings and data that is not critical. The following types are supported by NSUserDefaults:

NSString
NSNumber
NSDate
NSDictionary
NSData
  • Pros

Relatively easy to store and retrieve data
Perfect for storing small size data (example: User’s Settings)
Easy to learn and implement

  • Cons

Not ideal to store large amount of data
Performance will decrease when storing large amount of data
Not ideal to store sensitive data

36
Q

What is the reuseIdentifier used for

On a UITableViewCell constructor:

  • (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

What is the reuseIdentifier used for?

A

The reuseIdentifier is used to indicate that a cell can be re-used in a UITableView. For example when the cell looks the same, but has different content. The UITableView will maintain an internal cache of UITableViewCell’s with the reuseIdentifier and allow them to be re-used when dequeueReusableCellWithIdentifier: is called. By re-using table cell’s the scroll performance of the tableview is better because new views do not need to be created.

37
Q

What is the difference between viewDidLoad and viewDidAppear?

A

viewDidLoad is called when the view is loaded, whether from a Xib file, storyboard or programmatically created in loadView. viewDidAppear is called every time the view is presented on the device. Which to use depends on the use case for your data. If the data is fairly static and not likely to change then it can be loaded in viewDidLoad and cached. However if the data changes regularly then using viewDidAppear to load it is better. In both situations, the data should be loaded asynchronously on a background thread to avoid blocking the UI.

38
Q

What’s your preference when writing UI’s? Xib files, Storyboards or programmatic UIView?

A
  • Storyboard’s and Xib’s are great for quickly producing UI’s that match a design spec. They are also really easy for product managers to visually see how far along a screen is.
  • Storyboard’s are also great at representing a flow through an application and allowing a high-level visualization of an entire application.
  • Storyboard’s drawbacks are that in a team environment they are difficult to work on collaboratively because they’re a single file and merge’s become difficult to manage.
  • Storyboards and Xib files can also suffer from duplication and become difficult to update. For example if all button’s need to look identical and suddenly need a color change, then it can be a long/difficult process to do this across storyboards and xibs.
  • Programmatically constructing UIView’s can be verbose and tedious, but it can allow for greater control and also easier separation and sharing of code. They can also be more easily unit tested.
    Most developers will propose a combination of all 3 where it makes sense to share code, then re-usable UIViews or Xib files.
39
Q

What are different ways that you can specify the layout of elements in a UIView?

A

Here are a few common ways to specify the layout of elements in a UIView:

  • Using InterfaceBuilder, you can add a XIB file to your project, layout elements within it, and then load the XIB in your application code (either automatically, based on naming conventions, or manually). Also, using InterfaceBuilder you can create a storyboard for your application.
  • You can your own code to use NSLayoutConstraints to have elements in a view arranged by Auto Layout.
  • You can create CGRects describing the exact coordinates for each element and pass them to UIView’s - (id)initWithFrame:(CGRect)frame method.
40
Q

What is Cocoa and Cocoa Touch?

A

Cocoa vs Cocoa Touch

Cocoa Cocoa Touch

  1. Application development environments for OS X 1.1 Application development environments for iOS
  2. Includes the Foundation and AppKit frameworks 2.2 Includes Foundation and UIKit frameworks
  3. Used to refer any class/object which is based on the Objective-C runtime & inherits from the root class
  4. 3 Used to refer the application development using any programmatic interface
41
Q

Which JSON framework is supported by iOS?

A
  • iOS supports SBJson framework.
  • SBJson is a JSON parser and generator for Objective-C.
  • It provides flexible APIs and additional control, making JSON handling easier.
42
Q

What is the difference between atomic and nonatomic properties? Which is the default for synthesized properties?

A

Properties specified as atomic always return a fully initialized object. This also happens to be the default state for synthesized properties. But, if you have a property for which you know that retrieving an uninitialized value is not a risk (e.g. if all access to the property is already synchronized via other means), then setting it to nonatomic can give you better performance than atomic.

43
Q

Differentiate ‘app ID’ from ‘bundle ID’. Explain why they are used.

A

An App ID is a two-part string used to identify one or more apps from a single development team. The string consists of a Team ID and a bundle ID search string, with a period (.) separating the two parts. The Team ID is supplied by Apple and is unique to a specific development team, while the bundle ID search string is supplied by the developer to match either the bundle ID of a single app or a set of bundle IDs for a group of apps.

The bundle ID defines each App and is specified in Xcode. A single Xcode project can have multiple targets and therefore output multiple apps. A common use case is an app that has both lite/free and pro/full versions or is branded multiple ways.

44
Q

Which are the ways of achieving concurrency in iOS?

A

The three ways to achieve concurrency in iOS are:

Threads
Dispatch queues
Operation queues

45
Q

Explain the different types of iOS Application States.

A

The different iOS application states are:

  • Not running state: when the app has not been launched or was running but was terminated by the system.
  • Inactive state: when the app is running in the foreground but is currently not receiving events. An app stays in this state briefly as it transitions to a different state. The only time it stays inactive is when the user locks the screen or the system prompts the user to respond to some event such as a phone call or SMS message.
  • Active state: when the app is running in the foreground and is receiving events. This is the normal mode for foreground apps.
  • Background state: when the app is in the background and executing code. Most apps enter this state briefly on their way to being suspended. However, an app that requests extra execution time can remain in this state for some time. Also, an app being launched directly into the background enters this state instead of the inactive state.
  • Suspended state: A suspended app remains in memory but does not execute any code. When a low-memory condition occurs, the system may purge suspended apps without notice to make more space for the foreground app.
46
Q

Which is the framework that is used to construct an application’s user interface for iOS?

A

The UIKit framework is used to develop the application’s user interface for iOS. It provides event handling, drawing model, windows, views, and controls specifically designed for a touch screen interface.

47
Q

Which is the application thread from where UIKit classes should be used?

A

UIKit classes should be used only from an application’s main thread.

48
Q

Which API would you use to write test scripts to exercise the application’s UI elements?

A

UI Automation API is used to automate test procedures. JavaScript test scripts that are written to the UI Automation API simulate user interaction with the application and return log information to the host computer.

49
Q

When would you say that an app is not in a running state?

A

An app is said to be in ‘not running’ state in the following cases:
– When it is not launched.
– When it gets terminated by the system during running.

50
Q

What is Swift and what is Objective-C?

A

Objective-C is the primary programming language you use to write software for OS X and iOS. It’s a superset of the C programming language and provides object-oriented capabilities and a dynamic runtime. Objective-C inherits the syntax, primitive types, and flow control statements of C and adds syntax for defining classes and methods. It also adds language-level support for object graph management and object literals while providing dynamic typing and binding, deferring many responsibilities until runtime.

Swift is a new programming language for iOS, OS X, watchOS, and tvOS apps that builds on the best of C and Objective-C, without the constraints of C compatibility. Swift adopts safe programming patterns and adds modern features to make programming easier, more flexible, and more fun. Swift feels familiar to Objective-C developers and is friendly to new programmers.

51
Q

What is SpriteKit and what is SceneKit?

A

SpriteKit is a framework for easy development of animated 2D objects.

SceneKit is a framework inherited from OS X that assists with 3D graphics rendering.

SpriteKit, SceneKit, and Metal are expected to power a new generation of mobile games that redefine what iOS devices’ powerful GPUs can offer.

52
Q

What are iBeacons?

A

iBeacon.com defines iBeacon as Apple’s technology standard which allows Mobile Apps to listen for signals from beacons in the physical world and react accordingly. iBeacon technology allows Mobile Apps to understand their position on a micro-local scale, and deliver hyper-contextual content to users based on location. The underlying communication technology is Bluetooth Low Energy.

53
Q

What is an autorelease pool?

A

Every time – autorelease is sent to an object, it is added to the inner-most autorelease pool. When the pool is drained, it simply sends – releases to all the objects in the pool.
Autorelease pools are a convenience that allows you to defer sending -release until “later”. That “later” can happen in several places, but the most common in Cocoa GUI apps is at the end of the current run loop cycle.

54
Q

Differentiate between the ‘assign’ and ‘retain’ keywords.

A

Retain -specifies that retain should be invoked on the object upon assignment. It takes ownership of an object.
Assign – specifies that the setter uses simple assignment. It is used on attributes of scalar type like float, int.

55
Q

What are layer objects?

A

Layer objects are data objects which represent visual content and are used by views to render their content. Custom layer objects can also be added to the interface to implement complex animations and other types of sophisticated visual effects.

56
Q

Outline the class hierarchy for a UIButton until NSObject.

A

UIButton inherits from UIControl, UIControl inherits from UIView, UIView inherits from UIResponder, UIResponder inherits from the root class NSObject.

57
Q

You’ve declared view1 with var, and you’ve declared view2 with let. What’s the difference, 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?
A

Yes, the last line will compile. view1 is a variable, and you can reassign it to a new instance of UIView. With let, you can assign a value only once, so the following code would not 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 that the last line will compile:
let view2 = UIView()
view2.alpha = 0.5 // Yes!
58
Q
This complicated code sorts an array of names alphabetically. Simplify the closure as much as you can.
var animals = ["fish", "cat", "chicken", "dog"]
animals.sort { (one: String, two: String) -> Bool in
    return one < two
}
print(animals)
A

The type inference system automatically calculates both the type of the parameters in the closure and the return type, so you can get rid of them:
animals.sort { (one, two) in return one < two }

You can substitute the $i notation for the parameter names:
animals.sort { return $0 < $1 }

In single statement closures, you can omit the return keyword. The value of the last statement becomes the return value of the closure:
animals.sort { $0 < $1 }

Finally, since Swift knows that the elements of the array conform to Equatable, you can simply write:
animals.sort(by:

59
Q

What is an optional and which problem do optionals solve?

A

An optional lets a variable of any type represent a lack of value. In Objective-C, the absence of value is available only in reference types using the nil special value. Value types, such as int or float, do not have this 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, indicating a lack of value.

60
Q

What are generics and which problem do they solve?

A
In Swift, you can use generics in both functions and data types, e.g. in classes, structures or enumerations.
Generics solve the problem of code duplication. When you have a method that takes one type of parameter, it's common to duplicate it to accommodate a parameter of a different type.
For example, in the following code the second function is a "clone" of the first, except it 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

By adopting generics, you can combine the two functions into one and keep type safety at the same time. Here's the generic implementation:
func areTheyEqual(_ 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.

61
Q

In some cases, you can’t avoid using implicitly unwrapped optionals. When? Why?

A

The most common reasons to use implicitly unwrapped optionals are:

  • When you cannot initialize a property that is not nil by nature at instantiation time. A typical example is an Interface Builder outlet, which always initializes after its owner. In this specific case — assuming it’s properly configured in Interface Builder — you’ve guaranteed that the outlet is non-nil before you use it.
  • 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, you mark one side of the reference as unowned, while the other uses an implicitly unwrapped optional.
62
Q

What are the various ways to unwrap an optional? How do they rate in terms of safety?
var x : String? = “Test”

Hint: There are seven ways.

A

Forced unwrapping — unsafe.
let a: String = x!

Implicitly unwrapped variable declaration — unsafe in many cases.
var a = x!
Optional binding — safe.
if let a = x {
  print("x was successfully unwrapped and is = \(a)")
}
Optional chaining — safe.
let a = x?.count
Nil coalescing operator — safe.
let a = x ?? ""
Guard statement — safe.
guard let a = x else {
  return
}

Optional pattern — safe.
if case let a? = x {
print(a)
}

63
Q

What’s the difference between nil and .none?

A

There is no difference, as Optional.none (.none for short) and nil are equivalent.
In fact, this statement outputs true:
nil == .none

The use of nil is more common and is the recommended convention.

64
Q
Here's a model of a thermometer as a class and a struct. The compiler will complain about the last line. Why does it fail to compile?
Tip: Read the code carefully and think about it before testing it in a playground.
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)
A

The ThermometerStruct is correctly declared with a mutating function to change its internal variable temperature. The compiler complains because you’ve invoked registerTemperature on an instance created via let, which is therefore immutable. Change let to var to make the example compile.
With structures, you must mark methods that change the internal state as mutating, but you cannot invoke them from immutable variables.

65
Q

What will this code print and why?

A
It'll print: I love cars. The capture list creates a copy of thing when you declare the closure. This means that 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. Therefore, when you invoke the closure, it reflects any change to the variable. You can see this in the following code:
var thing = "cars"
let closure = {    
  print("I love \(thing)")
}

thing = “airplanes”

closure() // Prints: “I love airplanes”

66
Q
Here's a global function that counts the number of unique values in an array:
func countUniques(_ array: Array) -> Int {
  let sorted = array.sorted()
  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 sorted, so it restricts T to types that conform to Comparable.
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

A
You can rewrite the global countUniques(_:) as an Array extension:
extension Array where Element: Comparable {
  func countUniques() -> Int {
    let sortedValues = sorted()
    let initial: (Element?, Int) = (.none, 0)
    let reduced = sortedValues.reduce(initial) { 
      ($1, $0.0 == $1 ? $0.1 : $0.1 + 1) 
    }
    return reduced.1
  }
}

Note that the new method is available only when the generic Element type conforms to Comparable.

67
Q
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.

A

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
}

68
Q

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?

A
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.

69
Q

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?

A
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()
  }
}
70
Q

Can you add a stored property to a type by using an extension? How or why not?

A

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.

71
Q

What is a protocol in Swift?

A

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.

72
Q
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?

A
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

73
Q

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 Ints 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.

A

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.

74
Q

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()

A
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.

75
Q

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.

A
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)
}
76
Q

Are closures value or reference types?

A

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.

77
Q

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?

A

There’s an initializer for that:
UInt(bitPattern: Int)

making the implementation:
let myNegative = UInt(bitPattern: -1)
78
Q

Can you describe a circular reference in Swift? How can you solve it?

A

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.

79
Q
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 {
  case node(T, List)
}

This returns a compilation error. What is the missing keyword?

A

It’s the indirect keyword that allows for recursive enumeration cases like this:
enum List {
indirect case node(T, List)
}