Interview Questions Flashcards
What is the difference between Upcast and Downcast in Swift?
- 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
What’s the difference between == and ===?
== 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 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.
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 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?
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.
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?
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]]
What Classes and Structs have in common in Swift and what are their differences?
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.
What does the Swift mutating keyword mean?
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" } }
What is trailing closure syntax?
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.
What is a good use case for an inout parameter?
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
What is difference between as?, as! and as in Swift?
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).
What’s the difference between Self vs self?
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.
What’s the difference between a protocol and a class in Swift?
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.
When to use strong, weak and unowned references?
- 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.
When to use a set rather than an array in Swift?
You should use a set rather than an array if all the following criteria are true:
- You intend to add each item only once. Sets never allow duplicates.
- You don’t care about the order of the items in the set.
- You don’t need to use APIs that require arrays.
- 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.
When would you use self in a method?
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 } }
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?
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()
Explain when to use different Swift casting operators?
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.
Explain the difference between weak and unowned references. Provide an example.
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.
Is there a way to create an abstract class in Swift?
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
What is Copy on Write (Cow) in Swift?
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.
What is the difference between fileprivate and private?
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!" } }
What is the difference between open and public keywords in Swift?
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
What to use: [String: Any] or [String: AnyObject]?
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.
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?
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"
What’s the difference between Any and AnyObject?
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.
What is the use of Hashable protocol?
What’s the difference between init?() and init()?
What is the difference between fileprivate and private?
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!" } }
What is Copy on Write (Cow) in Swift?
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.
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?
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()
When would you use self in a method?
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 } }