# iOS Interview materials for Senior Developers
## Theory:
### Memory management: (I)
* How memory is managed on iOS? (ARC, strong vs weak references)
* Do we have to use weak/unowned self in every escaping closure? (*)
* What are the main differences between value types and reference types? (*)
* Where is struct and class stored in memory? (*)
* What is `Copy on Write`? (*)
* What happens if a struct has a closure as a property? Where is it stored?
* What is the difference between @escaping and @nonescaping Closures in Swift?
### Swift lang (A)
* What is an optional and how does it work under the hood (*)
### Concurrency: (A)
* Could you compare GCD, Operations and Swift Concurrency (*)
* What are the main problems while dealing with multithreaded applications? And how we can solve them? (*)
* Can we cancel tasks that we schedule with GCD? (*)
* How do we pass data from one operation to another operation? (*)
* Explain `Runloop`
* Explain QoS (optional)
### Database: (I)
* Explain when to use various storage mechanisms in iOS? (*)
* How does Realm store data? (*)
* What is the main difference between CoreData and Realm?
* What are delete rules in Core data? (`Deny`, `Nullify`, `Cascade`, `No action`)
* How to do Core Data Migrations?
* Lightweight VS Heavy migrations?
* What is the best way to do multi threading in Core Data?
### UI:
* What is the Responder Chain? (optional)
### SwiftUI (*)
* Any problems you faced while using SwiftUI? (*)
* What does ObservableObject protocol conformance give you? (*)
* What is difference between StateObject and ObservedObject? (*)
* Can init of a view struct be called multiple times? (*)
* How can we port SwiftUI views into UIKit and vice versa? (*)
* What is a UIHostingController?
### DI (I)
* What is DI and why do we need it? (*)
* List techniques of using DI (*)
### SOLID (I)
* Explain Interface Segregation Principle
### Design patterns (I)
* What is an adapter pattern and how it can be useful?
### Architecture: (A + I)
* Which architecture is best (MVC/MVVM/MVP/VIPER/Your own) and why it is best? (*)
* If you were to write an app from scratch, which architecture would you choose and why? (*)
* Would you architect an app differently if we use SwiftUI instead of UIKit? (*)
* Explain what Clean Archiecture and what it tries to achieve. What is the difference between traditional MVC/MVVM/MVP and etc.?
### Git: (A)
* What is trunk based development?
* What is an ideal pull request in your opinion?(*)
* What do you look for when doing code review? (*)
### Testing: (I)
* Explain what is the benefit of testing our own code (*)
* What kind of testing strategies do you know (*)
* UI testing is a powerful technique to decouple behavior from implementation (if we change the implementation but keep the same behavior, tests should pass). What problems can we encounter while using UI tests as a main strategy? (*)
### CD (I)
* Could you explain what is CD? What is difference between Continuous Delivery and Deployment?
* How can we achieve CD in iOS?
* Could you explain a CI/CD pipeline you used in your previous projects?
* Combine questions into 1 (*)
### Management:
* How do you estimate tasks?
### Other
* What is the difference between the UIApplicationDelegate and SceneDelegate?
* How many windows can we have in iOS apps?
## Live-coding/refactoring:
### Question #1:
```swift
class API {
func fetchList(completion: @escaping ([String]) -> Void) {
completion([
"Dummy 1",
"Dummy 2",
"Dummy 3",
])
}
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView = UITableView()
var list: [String] = []
override func viewDidLoad() {
API().fetchList { list in
self.list = list
self.tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let id = list[indexPath.row]
let nextVC = NextViewController()
nextVC.id = id
navigationController?.pushViewController(nextVC, animated: true)
}
}
class NextViewController: UIViewController {
var id: String?
}
```
### Question #2:
We have to handle error state in different screens and we use `BaseViewController` inheritance for this. Do you think this is the most optimal solution to this problem at hand?
```swift
class BaseViewController: UIViewController {
let errorView: UIView = {
let view = UIView()
view.backgroundColor = .red
view.isHidden = true
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(errorView)
errorView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
errorView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8),
errorView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8),
errorView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8),
errorView.heightAnchor.constraint(equalToConstant: 40)
])
}
}
class LoginViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
errorView.backgroundColor = .systemPink
}
}
class LogoutViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
errorView.backgroundColor = .purple
}
}
```
### Question #3:
So we have a screen where we should load articles and news. However, before loading, we should check if the user is authenticated or not. For separating concerns, we are using MVVM architecture and let the view model decide to load data for us and check if the user is authenticated.
```swift=
// MARK: - Articles
struct Article: Codable {
let id: UUID
let title: String
}
// MARK: - News
struct News: Codable {
let id: UUID
let title: String
let description: String
let publishedDate: String
let authorName: String
}
protocol LoaderService {
func loadArticles(completion: @escaping (Result<[Article], Error>) -> Void)
func loadNews(completion: @escaping (Result<[News], Error>) -> Void)
func isUserAuthenticated(userID: String, completion: @escaping (Result<Void, Error>) -> Void)
}
class ViewModelLoader: LoaderService {
func loadArticles(completion: @escaping (Result<[Article], Error>) -> Void) {
//....
}
func loadNews(completion: @escaping (Result<[News], Error>) -> Void) {
//....
}
func isUserAuthenticated(userID: String, completion: @escaping (Result<Void, Error>) -> Void) {
//....
}
}
protocol ArticlesAndNewsView: AnyObject {
func didReceiveData(news: [News], articles: [Article])
}
class ArticlesAndNewsViewModel {
var userID: String?
weak var view: ArticlesAndNewsView?
func loadData() {
let loader = ViewModelLoader()
if let id = userID {
loader.isUserAuthenticated(userID: id) { authResult in
switch authResult {
case .success:
loader.loadArticles { articlesResult in
switch articlesResult {
case let .success(articles):
loader.loadNews { [unowned self] newsResult in
switch newsResult {
case let .success(news):
view?.didReceiveData(news: news, articles: articles)
case let .failure(error):
print("Failed to load articles with error: \(error)")
}
}
case let .failure(error):
print("Failed to load news with error: \(error)")
}
}
case let .failure(error):
print("User authentication error: \(error)")
}
}
}
}
}
class ArticlesAndNewsViewController: UIViewController {
var viewModel: ArticlesAndNewsViewModel!
convenience init() {
self.init()
viewModel = ArticlesAndNewsViewModel()
}
override func viewDidLoad() {
super.viewDidLoad()
viewModel.loadData()
}
}
extension ArticlesAndNewsViewController: ArticlesAndNewsView {
func didReceiveData(news: [News], articles: [Article]) {
//update UI
}
}
```
Follow up questions:
* We would like to load data asynchronously and not wait for the completion blocks to finish. How can we do it?
* We would like to navigate to Articles or News screen. Describe the navigation logic you would use in this case