Interview Questions

  • Open — With open access modifier, You can access all data members and functions within same and outside of the module (target). You can also subclass or override data member and function outside the module as well.
  • public — same as open, only difference is you can not subclass or override outside the module.
  • File-private — As the name say’s, data members and member functions are accessible within the same file.
  • Private — This is where you can have access within the scope of function body or class.

Questions: How can you avoid race conditions?

Answer:
A race condition can occur when multiple threads access the same data without synchronization and at least one access is a write. For example if you read values from an array from the main thread while a background thread is adding new values to that same array.

var queue = DispatchQueue(label: "messages.queue", attributes: .concurrent)  queue.sync {     
// Code for accessing data
}

queue.sync(flags: .barrier) {
// Code for writing data
}
  • URLSessionDataTask: Use this task for GET requests to retrieve data from servers to memory.
  • URLSessionUploadTask: Use this task to upload a file from disk to a web service via a POST or PUT method.
  • URLSessionDownloadTask: Use this task to download a file from a remote service to a temporary file location.
  1. All Architecture is design pattern but all design pattern can not be architecture. Like MVC can come under both. But singleton design pattern can not be an architecture pattern. MVC, MVVM all come under both.
  2. Architecture is base which everything else adhere to and design pattern is a way to structure classes to solve common problems.
  3. Architectural pattern is like a blue print and design pattern is actual implementation.
  4. Architecture comes in Designing phase and Design Patterns comes in Building phase.
  5. Architecture : how components should behave and communicate in the system, set the physical location of components and finally choose the tools in order to create components.
    Design : while architecture deals more with the wide picture, design should drill down into the details relating to implementing certain components. Designing of components end up with classes, interfaces, abstract classes and other OO feature in order to fulfil the given component tasks.
var numbers = [1,2,3]numbers.append(4) 
print(numbers) //[1,2,3,4]
numbers.append(contentsOf: 5...10)
print(numbers) //[1,2,3,4,5,6,7,8,9,10]

Question: open VS public access control ?

  • 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).
  • Consider framework or module Alpha with public class, public method, open class and open method, framework Beta imports Alpha, both classes and methods will be available to framework B but only open class is subclassable and open methods can be override.

Question: What are higher order functions? Give some examples of higher order functions in Swift. Explain one of them.

A higher order function is a function that takes one or more functions as arguments or returns a function as its result.

protocol Storage {
associatedType item
func addProduct(product: item)
}
Class ABC: Storage {
typealias Item: Int
func addProduct(product: Int) {
}
}
tableView.onNumberOfRows { [weak self] section in
return self?.dataModel.count ?? 0
}
protocol sample {
var count: Int { get }
func add(_ element: Int)
func subtract() -> Int
}
extension String: LocalizedError {
public var errorDescription: String? {
Return NSLocalizedString(self, comment:””)
}
}
  • Structures are value types, whereas classes are reference types.
  • Structures don’t support inheritance, classes do.
  • In class, we can create an instance with let keywords and attempt to mutate its property, whereas there is no mutability in structures.
  • Structures do not support typecasting, but classes do.
  • Structure do have deInit method while classes have.
  1. Protocols allow developers to write flexible and extensible code in Swift without having to compromise the language’s expressiveness.
  2. Multiple inheritance can be achieved by protocols as class , struct , enums can conform multiple protocols.
    https://www.toptal.com/swift/introduction-protocol-oriented-programming-swift
  • It handles the control state like enabled, disabled, focused, highlighted etc.
  • It handles events like touchDown, touchupInside, valueChanged, editing events for UITextField etc.
  • Adding target, removing the target, handling actions etc.
  1. Context is responsible to fetch, create, modify and delete data from the persistent store.
  2. context also ensure no object is fetched twice in the context.
  3. Changes made by context don't get saved directly to persistent store, we need to manually save them by calling the save() function on context.
  4. Context also has the capability to post the notification to which developer can listen and react accordingly.
  • Persistent Store Coordinator:
    It is a mediator between the persistent store and managed context object.
  • Managed Object Model
  1. It is an object that describe the schema, collection of data models that we use in application.
  • Persistent Object Store: It has all the records or Here we store the required data of the application that we can use offline as well
  1. No Action
  2. Nullify
  3. Cascade
  4. Deny

Question: What us fallthrough statement in swift ?

Answer: fallthrough statement is used in switch case to execute case statement which is next to matched case statement.
e.g

Question: What is singleton pattern in swift and how to create it ?

Answer: Singleton class can have only one instance throughout the lifetime of the application. It also provide the singular global state like UIApplication, NotificationCenter etc.

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

Question: Can enum have stored properties ?

Answer: No, enum can not have stored properties, It can have methods or computed properties.

Question: Can we make let as weak ?

Answer: No, we can not make a let as weak because weak must be a mutable variable and it may change at run time, when we declare a weak variable then it will become an optional and an optional may or may not have a value.

class SomeClass { }class SomeOtherClass {weak let someClassObj: SomeClass? = nil 
// error:
'weak' must be a mutable variable, because it may change at runtime
}

Question: Can we make let as unowned ?

Answer: Yes, we can make a let as unowned because unowned reference will always have a value and unowned is not an optional.

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {//return The number of rows in section.
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//return A configured cell object.
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
/AppData/Library/Preferences/<bundle-identifier>.plist

let array1 = [“abc”, “pa”, “pb”, “pc”, “pq”, “cds”]
var temp = array1.filter({$0.hasPrefix(“p”)})
var temp2 =

temp.sorted(by:{$0<$1}).map({$0.uppercased()})

print(temp2)

Question: Write a generic function
Answer:
Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define.

  1. let temporaryA = a
  2. a = b
  1. lazy stored property is a property whose initial value is not calculated until first time it is used.
  2. I just stopped the debugger in viewDidLoad. You can see that secondHintView has a memory as it was not lazy for the storage but hintView is still nil as it is a lazy one. The memory gets allocated once you use/access the lazy variables.
  3. Lazy properties are not thread safe because of not initialized automatically .
  4. → lazy will always be a variable not constant because its initial value will be calculated later.
  5. You can’t use it with computed properties . Because, a computed property returns the value every time we try to access it after executing the code inside the computation block.
  6. You can use lazy only with members of struct and class.

2. Unnamed Tuple

In unnamed tuple we don’t specify the name for it’s elements.

Question: What is de-initializer and how it is written in Swift?

A de-initializer is declared immediately before a class instance is de-allocated. You write de-initializer with the deinit keyword. Use it if you need to do some action or cleanup before deallocating the object.

  1. WillSet observer will called when a property is about to change and DidSet observer is called after a property has been changed.

struct S {

var stored: String {

willSet {

print(“willSet stored is now equal to \(self.stored)”)

print(“willSet stored will be set to \(newValue)”)

}

didSet {

print(“stored is now equal to \(self.stored)”)

print(“stored was previously set to \(oldValue)”)

}

}

}

var s = S(stored: “1”)

s.stored = “2”

Question: What is identity operator ( === )?
Answer: we can check the identity of one object is equal to the identity of another object.
e.g
“Shubham” === “Jain” — — → it will return true

  1. Return
  2. Break
  3. Continue
  4. FallThrough
  1. Protocol does not include implementation, we can only declare method and properties there. Protocol can be conform by a class, struct and enum in swift.
  2. Note — -> if we declare any property in protocol then that particular protocol can not be conformed by enums because enums must not contain any stored properties.
  1. example of stores properties in enum
  2. example of store property declare in protocol and conform in enum and class — use case
  3. Note- In class protocol variable need to provide initial value while conforming in class
  1. function parameters are constants by default so we can not modify it, if we try to modify then it will give below error
  2. But we can modify it using inout parameters, It will create a local copy of the argument and will modify it and when the function will return then again copied that modified value into original. This is called copy in copy out process.
  1. Typealias allow you to provide a new name to an existing data types.
  2. Aliased name can be used instead of existing data type throughout the project.
  3. Type alias do not create a new data type, it simply assign a new name to an existing data type.
  4. Main purpose of typealias is to make code more readable and clear in context of human understanding.
  5. We can create type alias for Built in data types (String, Int)
  1. How we can do error handling in swift?
  2. In Swfit, Error handling is done using by do try catch and throw

Q: SVN VS Git

SVN relies on a centralised system for version management. It’s a central repository where working copies are generated and a network connection is required for access.

Q: GCD VS NSOperation

GCD is a low-level C-based API.
NSOperation and NSOperationQueue are Objective-C classes.
NSOperationQueue is objective C wrapper over GCD. If you are using NSOperation, then you are implicitly using Grand Central Dispatch.

Q: Static Vs Dynamic typing

Static typing is when your type checking occurs at compile time. You must define a type for your variables inside of your code and any operations you perform on your data would be checked by the compiler.

Q: What is Downcasting ?

When we’re casting an object to another type in Objective-C, it’s pretty simple since there’s only one way to do it. In Swift, though, there are two ways to cast — one that’s safe and one that’s not .

  • as used for upcasting and type casting to bridged type
  • as? used for safe casting, return nil if failed
  • as! used to force casting, crash if failed. should only be used when we know the downcast will succeed.

Q: What is the Swift main advantage ?

  • Optional Types, which make applications crash-resistant
  • Built-in error handling
  • Closures
  • Much faster compared to other languages
  • Type-safe language
  • Unified Memory Management (Complete ARC)
  • Dynamic library inclusion (reduce size)
  • Supports pattern matching
  • Playground feature

Question: Extension in swift ?

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code. Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.)

  • Add computed instance properties and computed type properties
  • Define instance methods and type methods
  • Provide new initializers
  • Define subscripts
  • Define and use new nested types
  • Make an existing type conform to a protocol

Q: Non-Escaping and Escaping Closures

The lifecycle of a non-escaping closure is simple: Pass a closure into a function -> The function runs the closure (or not) -> The function returns

Q: map vs flatmap

Use map to loop over a collection and apply the same operation to each element in the collection. The map function returns an array containing the results of applying a mapping or transform function to each item

Q: filter VS reduce

Use filter to loop over a collection and return an Array containing only those elements that match an include condition.

  1. Single Responsibility:
    Each class should have one responsibility.
    Code example
// You have two responsiblities in this classstruct Person {
let name: String
let age: Int
func checkAge() -> String {
if age < 8 {
return "Underage"
} else {
return "Qualified"
}
}
}
let person = Person(name: "Kelvin", age: 27)
person.checkAge()
// One responsibility in one classstruct Person {  
let name: String
let age: Int
}
// another responsibility in another classstruct AgeVerifier {
func checkAge(age: Int) -> String {
if age < 8 {
return "Underage"
} else {
return "Qualified"
}
}
}
let person = Person(name: "Lexton", age: 1)let verifyAge = AgeVerifier()verifyAge.checkAge(age: person.age)
  • Open for extension
  • Closed for modification

Code example

protocol AnimalProtocol {
func makeSound() -> String
}
class Tiger: AnimalProtocol {
func makeSound() -> String {
return "Roar"
}
}
struct Zoo {
let animals: [AnimalProtocol]
func animalNoise() -> [String] {
return animals.map { $0.makeSound()
}
}
}
let tiger = Tiger()
var zooAnimals = Zoo(animals: [tiger])
zooAnimals.animalNoise() // [roar]
class Horse: AnimalProtocol { 
func makeSound() -> String {
return “Neigh”
}
}
let horse = Horse()
zooAnimals = Zoo(animals: [tiger, horse])
zooAnimals.animalNoise() // [roar, neigh]

The child class shouldn’t break the parent class’s type definitions

A subclass should be able to override the parent class method in a way that doesn’t break the functionality of the base class.The benefit of this principle is that when code is interchangeable, it becomes more reusable.
Code example

class Bird {
func makeNoise() {
print(“Chirp chirp”)
}
}
class Eagle: Bird {
override func makeNoise() {
print(“Almight eagle roar”)
}
}
// This is where it violates the Liskov Substitution as doing so will break the parent classclass Crow: Bird {override func makeNoise() {
fatalError(“I forgot what my sound is”)
}
}

Code example

Looking at the code below, logically speaking, we know baby can’t really go to work, but because we conform the Action protocol, we’re required to declare the method. So this is an example of having a method we’re not using.

protocol Action {
func eat()
func work()
}
class Adult: Action {
func eat() {
// adult eat
}
func work() {
// adult work
}
}
class Baby: Action {
func eat() {
// baby eat
}
func work() {
// baby can’t work
}
}
protocol EatAction {
func eat()
}
protocol WorkAction {
func work()
}
class Adult: EatAction, WorkAction {
func eat() {
// adut eat
}
func work() {
// adult work
}
}
class Baby: EatAction {
func eat() {
// baby eat
}
}

Code example

The problem with the code below is the high-level module DatabaseController is tightly coupled with the low-level module NetworkRequest.

class DatabaseController {private let networkRequest: NetworkRequest

init(network: NetworkRequest) {
self.networkRequest = network
}
func connectDatabase() {
networkRequest.connect()
}
}
class NetworkRequest {
func connect() {
// connect to the database
}
}
protocol Database {
func connect()
}
class DatabaseController {
private let database: Database

init(db: Database) {
self.database = db
}
func connectDatabase() {
database.connect()
}
}
class NetworkRequest: Database {
func connect() {
// Connect to the database
}
}

Quick Summary

In your own journey to become a better engineer, keep in mind the following SOLID principles.

  • Each class should have only one responsibility
  • The class should be open for extension but closed for modification
  • The child class shouldn’t break the parent class’s type definitions
  • Implement only what you need
  • Depend on abstractions, not on concretions

Unlisted

--

--

--

iOS Developer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Dependency Injection in Swift

Reporting test coverage for Swift packages without Xcode

How to switch the direction of Firestore in dev/main in iOS development and how to move Firestore…

Why coding macOS apps is hard 3 learnings from @JulienLacr0ix to crack it 🔥

What’s New in Swift 5.3?

SwiftUI custom OTP View, Firebase OTP authentication-Part 01

Configuring Voice Over to ignore sibling views when an overlapping view is present in Swift

Swift Review — Closure(2)

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store