Interview Questions and Answers in iOS — Part 4

Interview questions and answers in iOS in very simple language.

Naveen Sharma
18 min readJun 2, 2020
Interview Questions and Answers in iOS

Q. What is the difference between ANY and ANYOBJECT in Swift?
A. According to Apple’s Swift documentation:
Any can represent an instance of any type at all, including function types and optional types.
AnyObject can represent an instance of any class type.

Important Links:
https://www.hackingwithswift.com/example-code/language/whats-the-difference-between-any-and-anyobject

Q. Explain Priority Inversion and Priority Inheritance?
A. If high priority thread waits for low priority thread, this is called Priority Inversion. If low priority thread temporarily inherits the priority of the highest priority thread, this is called Priority Inheritance.

Q. What is the relation between iVar and @property?
A. iVar is an instance variable. It cannot be accessed unless we create accessors, which are generated by @property. iVar and its counterpart @property can be of different names.
iVar is always can be accessed using KVC.

//Instance Variable (iVar)
@interface Photo : NSObject {
NSString *photographer;
}
@end
//Property
@interface Photo : NSObject
@property (nonatomic, strong) NSString *photographer;
@end

Q. What is Hashable?
A. Hashable allows us to use our objects as keys in a dictionary. So we can make our custom types.

Q. Explain the Swift Standart Library Protocol?
A.
Equatable Protocol
Comparable Protocol
Sequence Protocol
Codable Protocol
Hashable Protocol

Q. What are Functions?
A. Functions are self-contained blocks of code that perform a specific task. We give a function a name that identifies what it does, and this name is used to “call” the function to perform its task when needed. Once a function is created, it can be reused over and over in our code. If we find ourselves repeating statements in our code, then a function may be the answer to avoid that repetition.
Pro Tip, Good functions accept input and return output. Bad functions set global variables and rely on other functions to work.

Q. What kind of high-order functions can we use on collection types?
A. Functions that take another function as a parameter, or return a function, as a result, are known as higher-order functions. Swift defines these functions as CollectionType.
The very basic higher-order function is a filter.

map(_:): Returns an array of elements after transforming each element in the sequence using the provided closure.

filter(_:): Returns an array of elements that satisfy the provided closure predicate.

reduce(_:_:): Returns a single value by combining each element in the sequence using the provided closure.

sorted(by:): Returns an array of the elements in the sequence sorted based on the provided closure predicate.

To see all methods available from Sequence, take a look at the Sequence docs.
For more detail: AppCoda

Q. What is the difference between Filter and Map Function?
A. Map, we pass in a function that returns a value for each element in an array. The return value of this function represents what an element becomes in our new array.
Filter, we pass in a function that returns either true or false for each element. If the function that we pass returns true for a given element, then the element is included in the final array.

Q. What is Closure?
A. Closures are self-contained blocks of functionality that can be passed around and used in our code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
They don’t have a name and can capture values from their surrounding context.
Closures are first-class and high order objects.
The parameters in closure expression syntax can be in-out parameters, but they can’t have a default value.
Variadic parameters can be used if we name the variadic parameter.
Tuples can also be used as parameter types and return types.

var storedClosure: (Int, Int) -> Int = { (number1, number2) in
return number1 + number2
}
storedClosure(number1: 5, number2: 9) // 14the example above can be simplified, and, yes, it is still called closure.// Shorter
var storedClosure: (Int, Int) -> Int = { return $0 + $1 }
// Super Short
var storedClosure: (Int, Int) -> Int = { $0 + $1 }

Closure By Apple

Q. Trailing Closures?
A. If we need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. A trailing closure is written after the function call’s parentheses, even though it is still an argument to the function. When we use the trailing closure syntax, we don’t write the argument label for the closure as part of the function call.

func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
//Here’s how we call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
// closure’s body goes here
})
//Here’s how we call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure’s body goes here
}

Q. Explain Autoclosures?
A.
@autoclosure creates an automatic closure around the expression. When we write an expression, @autoclosure it is automatically wrapped into a closure.

Q. First Class Function/Closure?
A. Swift functions and closure are first class because:
- assign a function/closure to a local variable.
- pass a function/closure as an argument.
- return a function/closure.

func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}

var increment = makeIncrementer()
increment(7)

A function can take another function as one of its arguments.

func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}

var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)

Q. Higher Order Function/Closure?
A. Swift functions and closure are higher order because we can pass function/closure into another function/closure as a parameter or even return them.
The very basic higher-order function is a filter.

Q. What’s Completion Handler?
A. Completion handlers are super convenient when our app is making an API call, and we need to do something when that task is done, like updating the UI to show the data from the API call.

Q. What is the difference between Non-Escaping and Escaping Closures?
A.
- Closure parameters are non-escaping by default, if we wanna escape the closure execution, we have to use @escaping with the closure parameters.
- A non-escaping closure is a closure that’s called within the function it was passed into, i.e. before it returns.
- An escaping closure is a closure that’s called after the function returns it was passed into. In other words, it outlives the function it was passed to.
- A closure is said to escape a function when the closure is passed as an argument to the function but is called after the function returns. When we declare a function that takes a closure as one of its parameters, we can write @escaping before the parameter’s type to indicate that the closure is allowed to escape.
- A good example of an escaping closure is a completion handler. It’s executed in the future when a lengthy task completes, so it outlives the function it was created in. Another example is asynchronous programming: a closure that’s executed asynchronously always escapes its original context.
- Marking a closure with @escaping means we have to refer to self explicitly within the closure.

The lifecycle of the non-escaping closure:
1. Pass the closure as a function argument, during the function call.
2. Do some work in function and then execute the closure.
3. Function returns.

The lifecycle of the @escaping closure:
1. Pass the closure as a function argument, during the function call.
2. Do some additional work in function.
3. Function execute the closure asynchronously or stored.
4. Function returns.

Q. Functions and Closures are reference types why?
A. Whenever we assign a function or a closure to a constant or a variable, we actually set that constant or variable to be a reference to the function or closure.
As Closures are the reference type, so use [weak self] to prevent the memory leak.

Q. What is the difference between Delegates and Callbacks?
A. The difference between delegates and callbacks is that with delegates, the Network Service is telling the delegate “There is something changed.” With callbacks, the delegate is observing the Network Service.
Check this out
Also, Check this out

Q. Access Control in Swift?
A. Access control restricts access to parts of our code from code in other source files and modules. This feature enables us to hide the implementation details of our code and to specify a preferred interface through which that code can be accessed and used.
In Swift 3 and swift 4, we have open, public, internal, fileprivate, and private for access control. Open access is the highest (least restrictive) access level and private access is the lowest (most restrictive) access level.
Almost all entities in our code have a default access level of internal if we do not specify an explicit access level ourselves.

1. open (least restrictive) Enable an entity to be used outside the defining module (target).

2. public (least restrictive) Like open access level, public access level enables an entity to be used outside the defining module (target). But open access level allows us to subclass it from another module wherein public access level, we can only subclass or override it from within the module it is defined.

So in simple words:
- public classes and class members can only be subclassed and overridden within the defining module (target).
- open classes and class members can be subclassed and overridden both within and outside the defining module (target).

3. internal (default access level) internal is the default access level. Internal classes and members can be accessed anywhere within the same module(target) they are defined.

4. fileprivate Restricts the use of an entity to its defining source file. This means the function defined with a fileprivate access level can only be accessed from within the swift file where it is defined.

5. private (most restrictive) Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file.

Important Before swift 4, the private access level didn’t allow the use of a class member inside the extension of the same class.

public private(set) means getter is public, but the setter is private.

Q. What is the NSCoder class for?
A. NSCoder is an abstract class, which represents a stream of data. They are used in archiving and unarchiving objects.

Q. Explain JSONEncoder and JSONDecoder?
A. Codable protocol is added with Xcode 9, iOS 11, and Swift 4.
Codable is used to make our data types encodable and decodable for compatibility with external representations such as JSON.
Codable combines the Encodable and Decodable protocols.
JSONEncoder converts our type to Data and JSONDecoder converts Data to our type.
typealias Codable = Encodable & Decodable
If we want our type to be codable, the simplest way to do it is by conforming to Codable and making sure all its stored properties are also codable.

Q. What is the design pattern?
A. Design patterns are reusable solutions to common problems in software design. They’re templates designed to help us write a code that’s easy to understand and reuse. Most common Cocoa design patterns:

- Creational: Creational patterns provide various object creation mechanisms, which increase flexibility and reuse of existing code.
Singleton, Factory, Abstract Factory, Builder, Prototype

- Structural: Structural patterns explain how to assemble objects and classes into larger structures while keeping these structures flexible and efficient.
MVC, MVP, MVVM, VIPER, Clean Swift, Facade, Decorator, Adapter, Bridge, Composite, Flyweight, Proxy

- Behavioral: Behavioral design patterns are concerned with algorithms and the assignment of responsibilities between objects.
Observer, Memento, Chain of Responsibility, Command, Iterator, Mediator, State, Strategy, Template Method, Visitor

Q. What is the Singleton Pattern?
A. The Singleton design pattern ensures that only one instance exists for a given class and there’s a global access point to that instance. It usually uses lazy loading to create a single instance when it’s needed the first time.
The singleton class returns the same instance no matter how many times an application request it.
Note: Apple uses this approach a lot. For example: UserDefaults.standard, UIApplication.shared, UIScreen.main, FileManager.default all return a Singleton object.

final class Singleton {
static let sharedInstance = Singleton()
private init() {} // init should be private
}

Any variable declared with the let keyword is a constant and, therefore, read-only and thread-safe.
The static keyword makes sure it is lazily initialized inside a dispatch_once block. Static is internally final by default.
Making the init method as private so that nobody can access the init() method directly and create a new instance of the Singleton class.

Q. What is the Facade Design Pattern?
A. The facade design pattern provides a single interface to a complex subsystem. Instead of exposing the set of classes and their APIs, we only expose one simple unified API to the user.

Q. What is the Factory Design Pattern?
A. The factory design pattern makes the codebase more flexible to add or remove new types. To add a new type, we just need a new class for the type and a new factory to produce it.

Q. What is the Decorator Design Pattern?
A. The Decorator design pattern dynamically adds behaviors and responsibilities to an object without modifying its code. It’s an alternative to subclassing where we modify a class’s behavior by wrapping it with another object.
In Objective-C, there are two very common implementations of this pattern: Category and Delegation. In Swift, there are also two very common implementations of this pattern: Extensions and Delegation.

Q. What is Delegation?
A. Delegation is a mechanism in which one object acts on behalf of or in coordination with another object.
or
Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated.

Q. What is the Adapter Design Pattern?
A. The Adapter design pattern allows classes with incompatible interfaces to work together. It wraps itself around an object and exposes a standard interface to interact with that object. Ex: Protocols.

Q. What is Observer Design Pattern?
A. In the Observer design pattern, one object notifies other objects about any state changes. The objects involved don’t need to know about one another — thus encouraging a decoupled design.
Cocoa implements the observer pattern in two ways: Notifications and Key-Value Observing (KVO).

Q. What is the Memento Design Pattern?
A. In the Memento design pattern, we save our stuff somewhere. Later on, this externalized state can be restored without violating encapsulation; that is, private data remains private. One of Apple’s specialized implementations of the Memento design pattern is Archiving, on the other hand, iOS uses the Memento design pattern as part of State Restoration.

Q. Explain MVC Design Pattern?
A. The Model View Controller design pattern is a popular way to make logical division among class responsibility. There are three types of objects used in MVC:
Model: A model object is usually a subclass of NSObject. It holds our application data and defines how to manipulate it.
View: A View object is a subclass of UIView. The view made up of windows, controls, and other elements that the user can see and interact with.
Controller: A Controller object is usually a subclass of NSObject. It contains the code that binds together the model and view. It contains the business logic of the program.

Expected Cocoa MVC
Realistic Cocoa MVC

Q. Explain the MVP Design Pattern?
A.

MVP Design Pattern

Q. Explain the MVVM Design Pattern?
A.

MVVM Design Pattern

Q. KVC and KVO?
A. KVC stands for Key-Value Coding. KVC is a form of coding that allows us to access an object’s properties indirectly using strings instead of the property’s accessors or instead of accessing the variables directly. To enable such a mechanism, our classes must comply to the NSKeyValueCoding informal protocol.
self.setValue: “Stark” for key: “lastName”
[self setValue:@”This is a text” forKeyPath:@”self.model.property”];

KVO stands for Key-Value Observing and notifies about changes to the properties of other objects.
Key-value observing is a Cocoa programming pattern we use to notify objects about changes to properties of other objects. It’s useful for communicating changes between logically separated parts of our app — such as between models and views. We can only use key-value observing with classes that inherit from NSObject.
let options = NSKeyValueObservingOptions([.New, .Old, .Initial, .Prior])
self.model.addObserver(self, forKeyPath: self.model.property, options: options, context: nil)

Q. What is a key & KeyPath?
A. Key: Simply “Key” specifies a single property, the one we want to set a value or get one from. So its name should be the same as the property’s name.
Ex:
self.setValue: “Stark” for key: “lastName”

KeyPath: A KeyPath is formed with the dot-syntax by following the substrings, so it is not a single word/string. Key-path represents all the properties of an object, which comes in the way until to reach the desired value/property.
Ex:
var myProfile: Profile
self.setValue: “Baratheon” for keyPath: “myProfile.customProfile.lastName”

Q. What is Concurrency?
A. Execute multiple tasks at the same time in a scalable manner.
Here are a few more terminologies:
Process: An instance of an executing app
Thread: Path of execution for code
Multithreading: Multiple threads or multiple paths of execution running at the same time.
Concurrency: Execute multiple tasks at the same time in a scalable manner.
Queues: Queues are lightweight data structures that manage objects in the order of First-in, First-out (FIFO).
Synchronous vs Asynchronous tasks.

Q. What is Queues?
A. Queues are lightweight data structures that manage objects in the order of First-in, First-out (FIFO).

Q. What mechanisms does iOS provide to support multi-threading?
A. NSThread, NSOperationQueue, GCD

Q. Grand Central Dispatch (GCD)?
A. GCD is the marketing name for libdispatch, Apple’s library that provides support for concurrent code execution on multicore hardware on iOS and Mac OS.

GCD is a library that provides a low-level and object-based API to run tasks concurrently while managing threads behind the scenes.

It introduced in iOS 3.2 and it is c level API.

GCD provides Dispatch Queues to handle blocks of code that can be executed synchronously or asynchronously, either on the main or on a background thread. A dispatch queue is responsible for executing a task in the first-in, first-out order.

All dispatch queues are themselves thread-safe.

Serial Dispatch Queue A serial dispatch queue runs tasks one at a time in the FIFO order.

Concurrent Dispatch Queue A concurrent dispatch queue runs as many tasks as it can, without waiting for the started tasks to finish. These tasks can finish in any order but dequeue in FIFO order.

Main Dispatch Queue A globally available serial queue that executes tasks on the application’s main thread.

The main queue is automatically created by the system and associated with our application’s main thread.

The simplest way to create a new dispatch queue is the following:
let queue = DispatchQueue(label: “com.appname.queuename”)

Quality of Service (QoS): (Available in iOS 8 and later.) Quality of service (QoS) class allows us to categorize work to be performed by NSOperation, NSOperationQueue, NSThread objects, dispatch queues, and pthreads (POSIX threads). QoS is an enum with specific cases, and by providing the proper QoS value upon the queue initialization, we specify the desired priority. If no QoS is defined, then a default priority is given by the queue. Here are all cases from highest to lowest priority: userInteractive, userInitiated, default, utility, background, unspecified.

Note: The default QoS for the NSOperation class is NSQualityOfServiceBackground.

Here is the example to create dispatch queue with QoS
let queue1 = DispatchQueue(label: “com.appname.queue1”, qos: DispatchQoS.userInitiated)
let queue2 = DispatchQueue(label: “com.appname.queue2”, qos: DispatchQoS.userInitiated)

Concurrent Queues: Here is the code to make the dispatch queue concurrent.
let anotherQueue = DispatchQueue(label: “com.appname.anotherQueue”, qos: .utility, attributes: .concurrent)

There’s a new argument in the above initialization: The attributes parameter. When this parameter is present with the concurrent value, then all tasks of the specific queue will be executed simultaneously. If we don’t use this parameter, then the queue is a serial one. Also, the QoS parameter is not required, and we could have omitted it in this initialization without any problem.
The attributes parameter can also accept another value named initiallyInactive. By using that, the execution of the tasks doesn’t start automatically, instead, the developer has to trigger the execution.
The question now is, how can we have a concurrent queue while it’s initially inactive? Simply, we provide an array with both values, instead of providing a single value as the argument for the attributes parameter:

let anotherQueue = DispatchQueue(label: “com.appname.anotherQueue”, qos: .userInitiated, attributes: [.concurrent, .initiallyInactive])

Accessing the Main and Global Queues
Accessing the main queue from any other queue is simple as shown in the next snippet, and upon call we specify if it’s a synchronous or an asynchronous execution:
DispatchQueue.main.async {
// Do something
}

DispatchQueue.main.sync {
// Do something
}

GCD automatically create four dispatch queue that are global to our app and are differentiated only by their priority level. We don’t need to retain and release these four queues.
let globalQueue = DispatchQueue.global()
let globalQueue = DispatchQueue.global(qos: .userInteractive)
let globalQueue = DispatchQueue.global(qos: .userInitiated)
let globalQueue = DispatchQueue.global(qos: .utility)
let globalQueue = DispatchQueue.global(qos: .background)

when ARC is enabled, dispatch object is retained and release automatically.
When ARC is not enabled, we use dispatch_retain and dispatch_release function to retain and release the dispatch object.
We can not use Core Foundation retain/release function.
dispatch_retain, dispatch_release, dispatch_resume, dispatch_suspend are few function for dispatch objects.

Q. dispach_once()?
A. dispatch_once() executes a block once and only once in a thread-safe manner.

Q. What is DispatchGroup?
A. DispatchGroup allows for aggregate synchronization of work. We can use them to submit multiple different work items and track when they all complete, even though they might run on different queues. This behavior can be helpful when progress can’t be made until all of the specified tasks are complete.
The most basic answer: If we need to wait on a couple of asynchronous or synchronous operations before proceeding, we can use DispatchGroup.

Q. NSOperation and NSOperationQueue and NSBlockOperation?
A. NSOperation adds a little extra overhead compared to GCD, but we can add dependency among various operations and re-use, cancel or suspend them.

NSOperationQueue, It allows a pool of threads to be created and used to execute NSOperations in parallel. Operation queues aren’t part of GCD.

NSBlockOperation allows us to create an NSOperation from one or more closures. NSBlockOperations can have multiple blocks, that run concurrently.

Q. Readers-Writers?
A. Multiple threads reading at the same time while there should be only one thread writing. The solution to the problem is a readers-writers lock which allows concurrent read-only access and exclusive write access. Terminology;

Race Condition A race condition occurs when two or more threads can access shared data and they try to change it at the same time.

Deadlock A deadlock occurs when two or sometimes more tasks wait for the other to finish, and neither ever does.

Readers-Writers problem Multiple threads reading at the same time while there should be only one thread writing.

Readers-writer lock Such a lock allows concurrent read-only access to the shared resource while write operations require exclusive access.

Dispatch Barrier Block Dispatch barrier blocks create a serial-style bottleneck when working with concurrent queues.

Q. Difference between Process and Thread?
A. Thread and Process are two closely related terms in multi-threading. The main difference between the two terms is that the threads are a part of a process, i.e. a process may contain one or more threads, but a thread cannot contain a process.

Q. Explain Dispatch Barriers?
A.
Dispatch barriers are a group of functions acting as a serial queue style objects. It creates asynchronous execution and helps us to make a thread-unsafe object thread-safe. Dispatch barriers guarantee no writing occurs while reading and no reading occurs while writing using concurrency.

Q. Please explain Swift’s pattern matching techniques?
A.
- Tuple patterns
are used to match the values of corresponding tuple types.
- Type-casting patterns allow us to cast or match types.
- Wildcard patterns match and ignore any kind and type of value.
- Optional patterns are used to match optional values.
- Enumeration case patterns match cases of existing enumeration types.
- Expression patterns allow us to compare a given value against the given expression.

Q. What’s the difference between optional nil and .None?
A. 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.

Q. What’s the difference between accessibilityLabel and accessibilityIdentifier?
A. accessibilityLabel is the value that’s read by VoiceOver to the end-user. As such, this should be a localized string. The text should also be capitalized. Because this helps with VoiceOver’s pronunciation. accessibilityLabel is used for testing and Visual Impaired users.

accessibilityIdentifier identifies an element via accessibility, but unlike accessibilityLabel, accessibilityIdentifier’s purpose is pure to be used as an identifier for UI Automation tests. We use value for the testing process.

Q. In-App Purchase?
A. We use the StoreKit Framework to support IAP in our App. There are four types of IAP available:

1. Consumable These can be bought more than once and can be used up. These are things such as extra lives, in-game currency, temporary power-ups, and the like.

2. Non-Consumable Something that we buy once, and expect to have permanently such as extra levels and unlockable content.

3. Non-Renewing Subscription Content that’s available for a fixed period of time.

4. Auto-Renewing Subscription A repeating subscription such as a monthly, yearly.

Q. Explain libssl_iOS and libcrypto_iOS?
A. These files are going to help us with on-device verification of our receipt verification files with In-App purchases.

Q. What is made up of NSError object?
A. There are three parts of the NSError object a domain, an error code, and a user info dictionary. The domain is a string that identifies what categories of errors this error is coming from.

Thank you for reading! If you liked this article, please clap to get this article seen by more people.
Please follow me on Medium by clicking Follow.
I’m also active on LinkedIn, Twitter, and GitHub.

--

--