├── Clean Architecture.png ├── README.md ├── URLSessionMock.png ├── appLifecycle.png └── viewControllerLifecycle.png /Clean Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanMaxwell/iOS_interview_questions/5fbb831a487847286db063bb415569f06693e192/Clean Architecture.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Technical 3 | 4 | ## 1. What frameworks you used in your iOS projects? 5 | You can specify frameworks like:Cancel changes 6 | UIKit, SwiftUI, Combine, AVFramework, PushNotification, CallKit, GCD, Core Bluetooth, etc. 7 | 8 | ## 2. How the Optional is implemented in Swift? 9 | ``` 10 | enum Optional 11 | { 12 | case none 13 | case some(Wrapped) 14 | } 15 | ``` 16 | ## 3. Is there a difference between .none and nil? 17 | 18 | No 19 | 20 | ## 4. Ways to unwrap optional variables 21 | ``` 22 | var a:Int? 23 | 24 | a! //1 25 | 26 | if let s = a { //2 27 | 28 | } 29 | 30 | if let a { //3 31 | 32 | } 33 | 34 | guard let s = a else { //4 35 | 36 | } 37 | 38 | a ?? 0 //5 39 | ``` 40 | 41 | ## 5. What's difference between reference and value types? What reference and value types you know? 42 | 43 | **Value types**: 44 | structs, enums, arrays, dictionaries, strings 45 | 46 | **Reference types**: 47 | classes, closures, NS types are all classes (NSString, for example), actors 48 | 49 | Two differences between value and reference types: 50 | 1) Value types are stored in Stack and reference types are stored in Heap. 51 | 2) If you assign one object to another for reference type, you just copy the reference, not value: 52 | 53 | ``` 54 | // Reference type example 55 | class C { var data: Int = -1 } 56 | var x = C() 57 | var y = x // x is copied to y 58 | x.data = 42 // changes the instance referred to by x (and y) 59 | println("\(x.data), \(y.data)") // prints "42, 42" 60 | ``` 61 | 62 | For value types you will copy the value of the variable. 63 | 64 | ## 6. What's difference between Class and Structure? 65 | 66 | * Structures are value types. 67 | * Classes are reference types. 68 | * Structures don’t support inheritance. 69 | * classes support inheritance. 70 | * Structures don’t support de-initializers. ( deinit ) 71 | * Classes support deinitializers. 72 | * Structures don’t follow Reference Counting. 73 | * Classes follow Reference Counting. 74 | * Mutating Keyword is needed to modify the property values in Structure’s instance methods. 75 | * No need of mutating keyword to modify the class variable’s value. 76 | 77 | 78 | ## 7. Do you know what copy-on-write means? 79 | If you assign one array to another (not only array, there are other objects), then the second object will refer to the first array address until the second array is not changed 80 | ``` 81 | func addressOf(_ o: UnsafeRawPointer) -> String { 82 | let addr = unsafeBitCast(o, to: Int.self) 83 | return String(format: "%p", addr) 84 | } 85 | 86 | 87 | var array = [1, 2, 3, 4, 5] 88 | addressOf(array) // 0x600002e30ac0 89 | 90 | var array2 = array 91 | addressOf(array2) // 0x600002e30ac0 92 | 93 | array2.append(6) 94 | addressOf(array2) // 0x6000026119f0 95 | ``` 96 | 97 | ### How it's implemented? 98 | A type contains isKnownUniquelyReferenced() method, which checks if the current instance is uniquely referenced or if a copy needs to be made. 99 | 100 | ## 8. Do you know what are SOLID principles? 101 | 102 | SOLID: 103 | 104 | ### S – single responsibility principle. 105 | It’s when a class has just one purpose. A class shouldn’t contain functions that could be moved to other classes 106 | 107 | ### O – open/closed principle (OCP) 108 | A class should be opened for extension, but closed for changes. 109 | 110 | Open closed principle allows to avoid this kind of code: 111 | ``` 112 | protocol SomeProtocol { 113 | } 114 | 115 | class A:SomeProtocol { 116 | func printClassAName() { 117 | print("I'm A") 118 | } 119 | } 120 | 121 | 122 | class B:SomeProtocol{ 123 | func printClassBName() { 124 | print("I'm B") 125 | } 126 | } 127 | 128 | class Caller { 129 | func printClassName(obj:SomeProtocol){ 130 | ////TO AVOID THIS KIND OF CODE!!!!! 131 | if let unwrappeObj = obj as? A { 132 | obj.printClassAName() 133 | } 134 | else if let unwrappeObj = obj as? B { 135 | obj.printClassBName() 136 | } 137 | 138 | } 139 | } 140 | ``` 141 | 142 | It should be changed like that to avoid changes in Caller class in the future: 143 | ``` 144 | protocol SomeProtocol { 145 | func printClassName() 146 | } 147 | 148 | class A:SomeProtocol { 149 | func printClassName() { 150 | print("I'm A") 151 | } 152 | } 153 | 154 | 155 | class B:SomeProtocol{ 156 | func printClassName() { 157 | print("I'm B") 158 | } 159 | } 160 | 161 | class Caller { 162 | func doSomething(obj:SomeProtocol){ 163 | print(obj.printClassName()) 164 | } 165 | } 166 | ``` 167 | This principle is similar with D (dependency inversion principle), but OCP is more general. The DIP is an extension of the OCP. 168 | 169 | 170 | ### L – Liskov principle. 171 | In simple words this principle says that you need to have a possibility to use a parent and a child classes without any difference. 172 | ``` 173 | Class A: SomeProtocol { 174 | 175 | } 176 | 177 | Class B: SomeProtocol { 178 | 179 | } 180 | let a = A() 181 | let b = B() 182 | 183 | var a:[SomeProtocol] = [a, b] 184 | ``` 185 | ### I – interface segregation. 186 | Classes SHOULDN'T implement protocol methods they don’t use. 187 | If we noticed this situation, just move these methods to a separate protocol. 188 | 189 | ### D – dependency inversion. 190 | It means that a class shouldn’t depend on low-level modules – they both should depend on an Abstraction 191 | 192 | For example: 193 | ``` 194 | class FileSystemManager { 195 | func save(string: String) { 196 | // Open a file 197 | // Save the string in this file 198 | // Close the file 199 | } 200 | } 201 | class Handler { 202 | let fileManager = FilesystemManager() 203 | func handle(string: String) { 204 | fileManager.save(string: string) 205 | } 206 | } 207 | ``` 208 | 209 | If in the future we’ll need to add other methods for saving data (data base, for example), we should inherit FilesystemManager from some Storage protocol and use it instead of FilesystemManager and other possible data saving ways 210 | ``` 211 | class FileSystemManager:Storage { 212 | func save(string: String) { 213 | // Open a file 214 | // Save the string in this file 215 | // Close the file 216 | } 217 | } 218 | 219 | class DataBaseManager:Storage { 220 | func save(string: String) { 221 | // Open DB 222 | // Save the data 223 | // Close DB 224 | } 225 | } 226 | 227 | class Handler { 228 | let storage:Storage 229 | func handle(string: String) { 230 | storage.save(string: string) 231 | } 232 | } 233 | ``` 234 | 235 | This principle is similar with OCP is more general. The DIP is an extension of the OCP. 236 | 237 | Difference is that OCP is for similar functions, but DIP deals with the same input data 238 | 239 | ### 8.1 What SOLID principles Apple broke in their practice? 240 | 241 | Apple broke open-closed principle when moved to newer Swift versions and single responsibility, because viewcontroller contains presentation logic and presentation layer inside. 242 | 243 | 244 | ## 9. What is Singleton? 245 | 246 | The main point of Singleton is to ensure that we initialized something only once and this "something" should be available from everywhere. For example, UIApplication.shared 247 | 248 | P.S.: ServiceLocator – is a singleton or an injected object with an array of some services. 249 | 250 | 251 | ## 10. How are you doing your code reviews? 252 | 253 | The best practice said that the code review should depend on CI/CD tests, a style guide, SOLID, and some linter (a syntax checker) 254 | 255 | ## 11. Application lifecycle 256 | 257 | Use this: 258 | 259 | ![Application Lifecycle](https://github.com/AlanMaxwell/iOS_interview_questions/blob/main/appLifecycle.png) 260 | 261 | ## 12. ViewController lifecycle 262 | 263 | * ViewDidLoad - Called when you create the class and load from xib. Great for initial setup and one-time-only work. 264 | * ViewWillAppear - Called right before your view appears, good for hiding/showing fields or any operations that you want to happen every time before the view is visible. Because you might be going back and forth between views, this will be called every time your view is about to appear on the screen. 265 | * ViewDidAppear - Called after the view appears - great place to start an animations or the loading of external data from an API. 266 | * ViewWillDisappear/DidDisappear - Same idea as ViewWillAppear/ViewDidAppear. 267 | * ViewDidUnload/ViewDidDispose - In Objective-C, this is where you do your clean-up and release of stuff, but this is handled automatically so not much you really need to do here 268 | 269 | ![ViewController lifecycle](https://github.com/AlanMaxwell/iOS_interview_questions/blob/main/viewControllerLifecycle.png) 270 | 271 | ### P.S.: View lifecycle in SwiftUI: Appearing, Updating, Disappearing 272 | 273 | ## // TODO: Can you say what ViewController lifecycle methods are calling when you started to segue from a view (A) to another view (B), but haven't finish it? 274 | 275 | ## 13. What architecture patterns you used? 276 | 277 | Better to mention MVC, MVVM, VIPER 278 | 279 | ## 14. What is VIPER? 280 | 281 | VIPER – is an architecture pattern with these parts: 282 | 283 | * R – router – an entry point 284 | * E – entity – model (like in MVC, for example) 285 | * P – presenter – holds the reference to interactor, to a router and to a view 286 | * Presenter uses data, received using fetching data functions from Interactor to update View. 287 | * V – view. But with additional protocol with updating functions to call. For example, if we want to show an alert in a view, then we should ask the presenter to do that 288 | * I – Interactor handles business logic and data retrieval 289 | 290 | ## 15. What is MVVM? 291 | MVVM - Model View ViewModel 292 | 293 | * **Model** - is the data layer. 294 | * **View** - is a view. 295 | * **ViewModel** - contains presentation logic (process data from Model to View, reacts on actions from the View and transfers these reactions to Model). 296 | 297 | In the code tree there should be three different directories: Models, Views, ViewModels. Each of your classes should be represented separately there. 298 | 299 | Sometimes it's wise to create an additional directory called Services, in which you can put your business logic. 300 | 301 | ## 16. What is MVVM-C? 302 | It is MVVM with Coordinator, where Coordinator is an object (in SwiftUI it's an EnviromnentObject), that is common for all Views, that is responsible for navigation. It switches views depending on some observable variable, usually Enum. 303 | 304 | 305 | ## 17. Who is an owner of data in MVVM? 306 | 307 | Model is the data itself. 308 | 309 | ## 18. MVC MVVM differences: 310 | 311 | The main difference between MVC and MVVM is the role of the controller and view model. 312 | In MVC, the Controller handles user input and updates the Model and View. In MVVM, the VIEW MODEL handles user input and updates the Model and View, and the view is responsible for displaying the data. 313 | 314 | ## 19. What NS prefix means in some Swift and Objective-C classes? 315 | It means next step (the name of one company) 316 | 317 | ## 20. How memory management works in iOS? (Automatic reference counter (ARC)) 318 | 319 | In this question it's better to tell about ARC and retain cycles. 320 | 321 | Short explanation: 322 | ARC automatically keeps track of the number of references to an object, and when that number reaches zero, it deallocates the object. 323 | Counter decreases after an object releases. 324 | Any object deallocates after the counter is 0. 325 | 326 | If two objects have a strong reference to each other – retain cycle. Use weak or unowned to avoid that. 327 | 328 | My advise is to watch this video from Apple: 329 | https://developer.apple.com/videos/play/wwdc2021/10216/ 330 | 331 | Weak links also considered, but in a separate weak references counter. 332 | 333 | ### 20.1 On what thread memory deallocates? 334 | On the main thread 335 | 336 | ### 20.2 What's difference between unowned and weak 337 | 338 | Weak variables are presented as optional if to take a look on its type 339 | Unowned variables are presented as usual (they can’t be nil)) 340 | 341 | Unowned works faster, because there is no optional chech, but it's less safer (if the object doesn't exist, we'll have a crash). So we can use it if we're sure that the object will not be nil or when performance is critical. 342 | 343 | ## 21. What is map, flatMap, compatMap, reduce. Difference between map, flatMap, compatMap 344 | 345 | ### Mathematically: 346 | 347 | map: 348 | ``` 349 | var arr:[Int] = [1, 2, 3] 350 | arr = arr.map { 351 | return $0+1 352 | } 353 | ``` 354 | 355 | flatMap (is equivalent to Array(s.map(transformation).joined())): 356 | ``` 357 | var arr:[Int] = [[1,2,3],[4,5,6]] 358 | arr = arr.flatMap { 359 | return $0 360 | } 361 | ``` 362 | 363 | compatMap - same as map, but filters nil values 364 | 365 | ### In Combine 366 | 367 | map is used to transform each value emitted by a publisher using a provided closure. The closure takes in a value emitted by the publisher and returns a new value. 368 | 369 | compatMap is similar to map, but it also filters out any values that are nil before emitting the new values 370 | 371 | flatMap returns a new publisher with an emitted value as a parameter: 372 | ``` 373 | private var imagesListSubject = PassthroughSubject() 374 | 375 | imagesListSubject 376 | .removeDuplicates() 377 | .flatMap { [unowned self] day in 378 | self.networkService.fetchDayImagesList(day: day) 379 | } 380 | ``` 381 | 382 | ## 21. What's difference between bounds and frame in UIView? 383 | 384 | The difference in coordinate system. Bounds refers to its coordinates relative to its own space (as if the rest of your view hierarchy didn’t exist), frame refers to its coordinates relative to its parent’s space. 385 | 386 | ## 22. How to make a multilevel dismiss in SwiftUI? (to dismiss multiple level navigation) 387 | 1) You can use @EnvironmentObject, because it's available in all nested views 388 | 2) You can transfer @Binding variable from the root view to new navigation levels and if you need, just toggle this variable 389 | 3) Use an architecture pattern in which you can just set a current view. Like VIPER, REDUX and Composable architecture 390 | 391 | 392 | ## 23. What is a View protocol in SwiftUI? 393 | In SwiftUI, the View protocol is the fundamental building block of layout and user interface. But without some content it can't exist 394 | 395 | 396 | ## 24. Why Views are structures in SwiftUI? 397 | * structs are simpler to work with and faster than classes 398 | * it takes less memory (it takes only what was set, without multilevel inheritance) 399 | * views that don’t mutate over time 400 | 401 | ## 25. Is there a way to use UIKit elements in SwiftUI? 402 | 403 | Yes. You should create a class that conforms to UIViewRepresentable and UIViewControllerRepresentable protocols. 404 | 405 | But this is a long story. If you are curious in implementation, just try to find a couple of examples. 406 | 407 | 408 | ## 26. Redux in iOS (example of button tapping) 409 | 410 | A simple example in which a button increments a counter. 411 | ``` 412 | // The state of the application 413 | struct AppState { 414 | var count: Int = 0 415 | } 416 | 417 | // The actions that can be dispatched to the store 418 | enum CounterAction: Action { 419 | case increment 420 | case decrement 421 | } 422 | 423 | // The reducer, which handles the actions and updates the state 424 | func counterReducer(action: Action, state: AppState?) -> AppState { 425 | var state = state ?? AppState() 426 | 427 | switch action { 428 | case let action as CounterAction: 429 | switch action { 430 | case .increment: 431 | state.count += 1 432 | case .decrement: 433 | state.count -= 1 434 | } 435 | default: 436 | break 437 | } 438 | 439 | return state 440 | } 441 | 442 | // The store, which holds the state and handles the actions 443 | let store = Store( 444 | reducer: counterReducer, 445 | state: nil 446 | ) 447 | 448 | // The view, which displays the state and dispatches actions 449 | struct ContentView: View { 450 | @ObservedObject var store: Store 451 | 452 | var body: some View { 453 | VStack { 454 | Text("Count: \(store.state.count)") 455 | Button("Increment") { 456 | self.store.dispatch(action: CounterAction.increment) 457 | } 458 | } 459 | } 460 | } 461 | ``` 462 | 463 | ## 27. Composable architecture 464 | * View sends events to Action 465 | * Action sends an action to a Reducer (keeps state of the app alive) 466 | * Reduces mutate State, sends a call to Effect (outside world), interacts with Environment (dependencies, that are helpful for testing) 467 | * State influence View 468 | 469 | ## 28. What asynchronous functionality is available in Swift? 470 | 471 | * DispatchQueue 472 | * DispatchGroup 473 | * Operation queues 474 | * delegate events 475 | * Timer operations 476 | * Push Notifications 477 | * Calendar Operations 478 | * Combine publisher that is sending data 479 | * async/await 480 | * Tasks - that are using with async/await 481 | * background tasks (separate mechanism that is useful when you run tasks for an application in background). It runs not so long, but sometimes it's useful if you wake up the application in background and want to do something for this period. 482 | 483 | A note: you should always update interface only on main thread (DispatchQueue.main), otherwise it can just stuck 484 | 485 | ## 29. What's difference between DispatchQueue, Operation queues, async/await? 486 | 487 | * Difference between DispatchQueue and async/await is in tasks scheduling. DispatchQueue create a separate thread for each waiting task, whereas async/await is trying to launch everything on just one thread by suspending waiting functions. So async/await reduces number of threads and the number of threads switching. 488 | https://developer.apple.com/videos/play/wwdc2021/10254/ 489 | * async/await is the language feature, DispatchQueue is a framework. 490 | * DispatchQueue and OperationQueue are used for managing work on threads, async/await is used for writing asynchronous code in a synchronous style. 491 | 492 | * DispatchQueue and OperationQueue difference - you can't cancel DispatchQueue tasks. So, DispatchQueue are better for short tasks that should have minimum performance and memory, OperationQueue are more suitable for long-running operations that may need to be cancelled or have complex dependencies 493 | 494 | 495 | ## 30. What is a dead lock? 496 | 497 | It's when two different threads want to access to a shared resource, but they are both waiting for each other to unlock. 498 | 499 | ## 31. What is a race condition? 500 | 501 | It's when two different threads write and read from a shared resource without syncronization. It leads to broked data. 502 | 503 | ## 32. How to launch a group of asyncronous tasks? 504 | 505 | If the order doesn't matter, you can just use DispatchQueue.main.async (or DispatchQueue.global.async). 506 | 507 | If order matters you can use DispatchGroup with DispatchQueue or Operation Queue. But what to choose depends on a task specific: when you use Operation Queue you will not be notified when these tasks are done, but in DispatchGroup you will be. And if you use DispatchGroup you can't cancel tasks execution, but for Operation Queue you can. 508 | 509 | Also, using Combine you can launch several tasks using "CombineLatest" 510 | 511 | ## 33. Can a DispatchQueue task be cancelled? 512 | 513 | No. But DispatchWorkItem can be cancelled. 514 | 515 | ## 34. What HTTP methods you know? 516 | 517 | * HTTP: 518 | * POST: Sends data to specific server to create or update information. 519 | * PUT: Sends data to specific server to create or update information without the risk of creating the resource more than once. 520 | * HEADER: Previews what the GET request response might be without the body of the text. 521 | * OPTIONS: Learns the communication channels used by the target source. 522 | * GET: Requests information from a specific source. 523 | * DELETE: Removes information. 524 | 525 | 526 | ## 35. How do you test network calls in Unit test? 527 | 528 | ### 1)You should mock network calls. 529 | ``` 530 | protocol NetworkServiceProtocol { 531 | func getDataFromServer(completion: @escaping (Result) -> Void) 532 | } 533 | ``` 534 | Then, create a mock implementation of the protocol that returns pre-defined data: 535 | 536 | ``` 537 | class MockNetworkService: NetworkServiceProtocol { 538 | func getDataFromServer(completion: @escaping (Result) -> Void) { 539 | let data = Data("Mocked data".utf8) 540 | completion(.success(data)) 541 | } 542 | } 543 | ``` 544 | Now, in your test case, you can inject the mock network service into your code: 545 | 546 | ``` 547 | func testGetDataFromServer() { 548 | let mockService = MockNetworkService() 549 | let viewModel = MyViewModel(networkService: mockService) 550 | viewModel.getDataFromServer() 551 | 552 | // Assert that the view model processed the mocked data correctly 553 | XCTAssertEqual(viewModel.result, "Mocked data") 554 | } 555 | ``` 556 | 557 | ### 2) You can mock not only network calls, you can mock entire classes using, for example, OCMock framework 558 | 559 | ### 3) Apple recommends to do something like this, to mock URLSession configuration 560 | 561 | ![URLSessionMock](https://github.com/AlanMaxwell/iOS_interview_questions/blob/main/URLSessionMock.png) 562 | 563 | https://developer.apple.com/videos/play/wwdc2018/417/ 564 | 565 | Here is the code example of mocked HTTP request using Combine: 566 | 567 | #### 568 | ``` 569 | import XCTest 570 | 571 | class MockURLProtocol: URLProtocol { 572 | static var requestHandler: ((URLRequest) throws -> (HTTPURLResponse, Data))? 573 | 574 | override class func canInit(with request: URLRequest) -> Bool { 575 | return true 576 | } 577 | 578 | override class func canonicalRequest(for request: URLRequest) -> URLRequest { 579 | return request 580 | } 581 | 582 | override func startLoading() { 583 | guard let handler = MockURLProtocol.requestHandler else { 584 | XCTFail("Received unexpected request with no handler set") 585 | return 586 | } 587 | do { 588 | let (response, data) = try handler(request) 589 | client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed) 590 | client?.urlProtocol(self, didLoad: data) 591 | client?.urlProtocolDidFinishLoading(self) 592 | } catch { 593 | client?.urlProtocol(self, didFailWithError: error) 594 | } 595 | } 596 | 597 | override func stopLoading() { 598 | } 599 | } 600 | 601 | enum ServiceError: Error, Equatable { 602 | case invalidURL 603 | case noInternetConnection 604 | case requestTimeout 605 | case networkError 606 | case statusCodeError(code: Int?) 607 | } 608 | 609 | final class NetworkLayerTests: XCTestCase { 610 | 611 | var mockedUrlSession: URLSession! 612 | 613 | override func setUpWithError() throws { 614 | //exit test if something failes 615 | self.continueAfterFailure = false 616 | 617 | let configuration = URLSessionConfiguration.ephemeral 618 | 619 | //set up a mock for url session 620 | configuration.protocolClasses = [MockURLProtocol.self] 621 | mockedUrlSession = URLSession(configuration: configuration) 622 | } 623 | 624 | struct UserProfile:Codable { 625 | var name:String? 626 | } 627 | 628 | class ProfileAPI { 629 | let url = URL(string: "https://testURL.com/user")! 630 | private var cancellable: AnyCancellable? 631 | 632 | // session to be used to make the API call 633 | let session: URLSession 634 | 635 | // Make the session shared by default. 636 | // In unit tests, a mock session can be injected. 637 | init(urlSession: URLSession = .shared) { 638 | self.session = urlSession 639 | } 640 | 641 | // get user profile from backend 642 | func getProfile(completion: @escaping (UserProfile) -> Void) { 643 | cancellable = session.dataTaskPublisher(for: url) 644 | .mapError { error -> ServiceError in 645 | switch error.code { 646 | case .notConnectedToInternet: 647 | return .noInternetConnection 648 | case .timedOut: 649 | return .requestTimeout 650 | default: 651 | return .networkError 652 | } 653 | } 654 | .tryMap { data, response in 655 | guard let httpResponse = response as? HTTPURLResponse, 656 | 200..<300 ~= httpResponse.statusCode else { 657 | throw ServiceError.statusCodeError(code: (response as! HTTPURLResponse).statusCode) 658 | } 659 | return data 660 | } 661 | .decode(type: UserProfile.self, decoder: JSONDecoder()) 662 | .receive(on: RunLoop.main) 663 | .catch { _ in Just(UserProfile()) } 664 | .sink { user in 665 | completion(user) 666 | } 667 | } 668 | } 669 | 670 | func testCase() throws { 671 | 672 | let example = UserProfile(name: "Some User") 673 | let mockData = try JSONEncoder().encode(example) 674 | 675 | //set return data in mock request handler 676 | MockURLProtocol.requestHandler = { request in 677 | let response = HTTPURLResponse(url: URL(string: "https://someURL.com/test")!, 678 | statusCode: 200, 679 | httpVersion: nil, 680 | headerFields: ["Content-Type": "application/json"])! 681 | return (response, mockData) 682 | } 683 | 684 | //this is simpler example, but without http-status mocking 685 | // MockURLProtocol.requestHandler = { request in 686 | // return (HTTPURLResponse(), mockData) 687 | // } 688 | 689 | // Set expectation. Used to test async code. 690 | let expectation = XCTestExpectation(description: "response") 691 | 692 | // Make mock network request to get profile 693 | // here we use the previously set mocked UrlSession 694 | let profileAPI = ProfileAPI(urlSession: mockedUrlSession) 695 | 696 | profileAPI.getProfile { user in 697 | // Test 698 | XCTAssertEqual(user.name, "Some User") 699 | expectation.fulfill() 700 | } 701 | wait(for: [expectation], timeout: 1) 702 | } 703 | } 704 | ``` 705 | ## 36. What is the role of the "final" word in the class? 706 | It prevents properties and functions from overriding. 707 | 708 | ## 37. What are lazy variables? 709 | They initialize after the first time they are calling. 710 | 711 | ## 38. Pros and cons of using UIKit and SwiftUI 712 | 713 | ## 39. Is there a difference between "Codable" and "Encodable & Decodable" protocol inheritance? 714 | No, Codable is a type alias for Encodable & Decodable 715 | 716 | ## 40. What are Encodable and Decodable protocols used for? 717 | 718 | protocol Decodable : allows to decode bytes to the type that inherits Decodable 719 | 720 | protocol Encodable : allows to represent a type as data bytes 721 | 722 | Oftenly they are used for interaction with JSON and plist. 723 | 724 | ### P.S.: There could be a related question, can we rename keys during encoding/decoding? 725 | Yes, we can using CodingKey syntax 726 | ``` 727 | struct Person: Decodable { 728 | var personName: String 729 | 730 | enum CodingKeys: String, CodingKey { 731 | case personName = "name" 732 | } 733 | } 734 | ``` 735 | 736 | ## 41. How to serialize a generic type? 737 | Two ways: 738 | 1) Automatic: when you just inherit a type from Codable and just encode (P.S.: all class fields should conform to Encodable) 739 | ``` 740 | class Example: Codable { 741 | let data: T 742 | 743 | init(data: T) { 744 | self.data = data 745 | } 746 | } 747 | 748 | let example = Example(data: ["John", "Doe", "john.doe@example.com"]) 749 | let encoder = JSONEncoder() 750 | let data = try encoder.encode(example) 751 | ``` 752 | 2) Manually - create a self written encode function. If you want to use, for example, not all fields 753 | ``` 754 | class Response: Encodable { 755 | let success: Bool 756 | let data: T 757 | 758 | let str:String = "" //extra field, which we don't use 759 | 760 | 761 | init(success: Bool, data: T) { 762 | self.success = success 763 | self.data = data 764 | } 765 | 766 | func encode(to encoder: Encoder) throws { 767 | var container = encoder.container(keyedBy: CodingKeys.self) 768 | try container.encode(success, forKey: .success) 769 | try container.encode(data, forKey: .data) 770 | } 771 | 772 | private enum CodingKeys: String, CodingKey { 773 | case success 774 | case data 775 | } 776 | } 777 | ``` 778 | 779 | ## 42. Hou would you explain App Transport Security (ATS) to a junior? 780 | ATS blocks insecure URLSession connections. (Security criteria are shown here https://developer.apple.com/documentation/security/preventing_insecure_network_connections) 781 | 782 | There are two ways to prevent connections blocking: 783 | 1) Set "Allow Arbitrary Loads" - it is not a good approach. It looks like that: 784 | ``` 785 | NSAppTransportSecurity 786 | 787 | NSAllowsArbitraryLoads 788 | 789 | 790 | ``` 791 | 792 | 2) You can set the exceptions. That is the good approach. It looks like that: 793 | ``` 794 | NSAppTransportSecurity 795 | 796 | NSAllowsArbitraryLoads 797 | 798 | NSExceptionDomains 799 | 800 | exception.com 801 | 802 | NSIncludesSubdomains 803 | 804 | NSExceptionAllowsInsecureHTTPLoads 805 | 806 | 807 | 808 | 809 | 810 | ``` 811 | 812 | 813 | ## 43. How would you explain Dependency Injection to a junior? 814 | Dependency Injection is an approach, when functionality of one entity depends on the other entity and the FIRST gets the SECOND as a parameter. 815 | 816 | I would provide an example of MVVM implementation, because link to ViewModel in View is a good example of Dependency Injection. 817 | 818 | Why it's needed? To divide the functionality to different reusable parts and also to increase testability. 819 | 820 | ## 44. What three types of Dependency Injection you know? 821 | 822 | * Constructor Injection: Dependency is passed to the object via its constructor. It used when the dependent object has to use the same concrete class for its lifetime. 823 | * Method Injection: dependency is passed to the object via a method. It's useful if different objects could be injected. For example, if the dependency is a notification, sometimes this may sent as an SMS, and other times as an email for the same dependent object. 824 | * Property Injection: If the dependency is selected and invoked at different places, we can set the dependency via a property exposed by the dependent object, which can then invoke it later 825 | 826 | ## 45. What's difference between @escaping and non-escaping closures? 827 | @escaping launches after the function ends, non-escaping - just after its call. 828 | 829 | ## 46. What's difference between inout parameter of the function and a usual parameter? 830 | 831 | ``` 832 | func example(_ a: Int, _ b: inout Int) {} 833 | ``` 834 | inout keyword allows to change the value of the parameter variable. 835 | 836 | ## 47. In SwiftUI how to draw 1 million rows in a list? 837 | 838 | 1) You can use List view element 839 | 2) ScrollView + LazyVStack views 840 | 841 | 842 | ## 48. Do classes support multilple inheritance in Swift? 843 | 844 | If to try to inherit from multiple classes, then NO. Swift classes don't support multiple inheritance. 845 | 846 | But you can inherit multiple protocols. 847 | 848 | ## 49. How to prevent a class inheritance? 849 | 850 | Using final keyword, like: 851 | ``` 852 | final class User { 853 | var name: String 854 | 855 | init(name: String) { 856 | self.name = name 857 | } 858 | } 859 | ``` 860 | 861 | ## 50. What is the default access level for class fields? 862 | internal 863 | 864 | ## 51. What is id in Objective-C? 865 | It is a generic type 866 | 867 | ## 52. What is responder chain? 868 | 869 | The responder chain is responsible to handle all the events (like touch and motion) in iOS apps. If any responder can't handle a specific action or event, the event is sent to the next responder of the list to handle it until the list ends. 870 | 871 | (conclusion taken from here: https://www.swiftanytime.com/blog/using-responders-and-the-responder-chain-to-handle-events) 872 | 873 | It starts handling this event from UIApplication and finishes at the target element. 874 | 875 | UIResponder abstract class responsible for some gesture events that we even can override. 876 | To pass this event to other elements in the chain, these events contain also a reference to "next" element. 877 | 878 | ### 52. What is Hit test? 879 | This method is called to determine which view should receive a touch event. By default, it returns the farthest descendant of the view hierarchy that contains a specified point. 880 | 881 | Here is an example: 882 | Imagine that you have two UIViews: a parent and a child. The child view is a subview of the parent view. 883 | Imagine that we tap the child view, but we want the parent view to be tapped instead. How to reach this behavior? 884 | 885 | You can achieve this behavior by overriding the hitTest(_:with:) method of the parent view to make the parent view receive touches that occur within the bounds of the child view: 886 | 887 | ``` 888 | 889 | class ParentView: UIView { 890 | override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 891 | // Check if the point is inside the bounds of the parent view 892 | if self.bounds.contains(point) { 893 | // Return self (parent view) as the view to receive the touch 894 | return self 895 | } 896 | 897 | // If the point is not inside the parent view, let the default behavior handle it 898 | return super.hitTest(point, with: event) 899 | } 900 | } 901 | 902 | class ChildView: UIView { 903 | // Your implementation for the child view 904 | } 905 | 906 | // Usage 907 | let parentView = ParentView() 908 | let childView = ChildView() 909 | 910 | parentView.addSubview(childView) 911 | ``` 912 | Now if we tap on the child view the parent view will be tapped instead 913 | 914 | ## 53. What is a zombie object? 915 | 916 | It's an object, which is called after there is no more strong reference to this object. 917 | 918 | ## 54. What's difference between Any and AnyObject? 919 | 920 | AnyObject refers to any instance of a class, Any - refers to any instance of any type: class, struct, enum, etc. 921 | 922 | ## 55. How to implement generic protocol? 923 | 924 | Using associatedtype. 925 | ``` 926 | protocol MyProtocol { 927 | associatedtype MyType 928 | func doSomething(with value: MyType) 929 | } 930 | 931 | class MyClass: MyProtocol { 932 | typealias MyType = T 933 | 934 | func doSomething(with value: T) { 935 | // Implementation 936 | print("Doing something with \(value)") 937 | } 938 | } 939 | ``` 940 | ## 56. How to share common files between different applications on one device? 941 | 942 | Using common App Groups for these applications. 943 | 944 | 945 | ## 57. What types of publishers Combine provides? 946 | 947 | * Publishers.Sequence: The Sequence publisher emits a sequence of values provided as an array or a sequence type. It's commonly used to emit a predefined set of values. 948 | * Publishers.Just: The Just publisher emits a single value and then finishes. It's similar to the Just publisher mentioned earlier but is a different implementation provided by the Combine framework. 949 | * Publishers.Future: The Future publisher represents a result or value that will be available in the future. It's useful when you want to create a publisher that produces a single value at some point in time. 950 | * Publishers.Timer: The Timer publisher emits a value after a specified time interval and then finishes. It's commonly used for creating time-based operations. 951 | 952 | ## 58. Why extension can't contain stored properties, but can contain computed variables? 953 | 954 | Because of memory management. When you define a stored property its size calculates, but extensions developed like that so they should affect existing memory layout. Calculated variables don't affect. 955 | 956 | ## 59. What are hot and cold signals in reactive programming? 957 | 958 | In reactive programming, the terms "cold" and "hot" signals refer to different ways of handling data streams. 959 | 960 | Cold Signals - they are data streams that start producing values only when a subscriber subscribes to them. Each subscriber receives its own independent stream of values. 961 | 962 | Better examples of cold signals include: 963 | Button taps: Each time a button is tapped, a new stream of events is created, and each subscriber receives the events starting from the moment they subscribed. 964 | Network requests: When making a network request, the response stream is typically cold. Each subscriber initiates its own network request and receives the response independently. 965 | 966 | Hot Signals - they are data streams that produce values regardless of whether there are active subscribers or not. Subscribers joining a hot signal receive only the values emitted after they subscribe. Hot signals share a single stream of values among multiple subscribers. 967 | 968 | Better examples of hot signals include: 969 | Notifications: System-wide notifications that can be observed by multiple components or modules in an application. Subscribers joining the notification stream receive only the notifications emitted after they subscribe. 970 | Sensor data: Continuous streams of data from sensors, such as GPS location updates or accelerometer readings, where the data is constantly being produced and can be observed by multiple parts of an application. 971 | 972 | ## 60. What SwiftUI property wrappers do you know? 973 | 974 | You can list those: 975 | * @State 976 | * @Binding 977 | * @ObservedObject 978 | * @StateObject 979 | * @EnvironmentObject - it is an observable object, which can be applied for several views and it affects these views simultaniously. 980 | 981 | About others - it described in further questions. 982 | 983 | ## 61. What's difference between @ObservedObject and @StateObject? 984 | 985 | @ObservedObject is used to keep track of an object that has already been created and passed as a parameter from the outside. 986 | @StateObject is similar to @ObservedObject but it differf how SwiftUI manages their lifecycle. 987 | 988 | SwiftUI is allowed to destroy a View in every moment. In this case if we created an @ObservedObject property, then it will be destroyed and recreated too. 989 | @StateObject fixes that. If the View will be destroyed and recreated, then this object will REMAIN in memory and the View won’t lose the data during redrawing. 990 | This works for child views, for example: if your child view has @StateObject property with some data, then if the parent redraws, then StateObject will not loose its value. But if the child view has an @ObservedObject property, then when the parent will be redrawn, then the child view will be redrawn too and @ObservedObject will be created again. 991 | 992 | 993 | ## 62. What's difference between @State and @Binding wrappers? 994 | 995 | @State is meant for simple value type properties, which can be changed within a View. If to use it with reference types then its changes will not redraw data on the View. 996 | @Binding is used to change properties bi-directionally. So, it can be used, for example, to change a property of a parent view from its child view. 997 | 998 | ## 63. What is Bytecode? 999 | 1000 | Middle code between the source code and machine code to allow to automatically compile an old application on the AppStore to new architectures. 1001 | 1002 | ## 64. What is Runloop? 1003 | It's an iOS system thread in which you can track states of other threads. For example, there you can make an ethernal check for some state. 1004 | 1005 | ## 65. What is dSYM? 1006 | It's a file with correspondence between source code and a binary of the application to make crash logs and debugging process readable. 1007 | 1008 | ## 66. What is autoreleasepool? 1009 | 1010 | In Swift language it allows to not to wait until operating system cleans the memory during some actions (a loop, in a loop for example) and cleans memory as soon as possible. 1011 | 1012 | ## 67. Methods Dispatch. What types of it you know? 1013 | 1014 | Static or Direct dispatch – fastest way of finding methods, because compiler knows method location from the beginning (scenario when a method hasn’t been overwritten (there is no inheritance)). So, value types have direct dispatch 1015 | 1016 | Dynamic or Table dispatch – happens in reference types – a method is searched in the table of function pointers (witness table) and then it’s invokes. When we create a subclass, we make a copy of this witness table. If we override some method, we override it in this table. 1017 | It’s slower than Static, but allows inheritance 1018 | 1019 | Message dispatch – more dynamic than Table dispatch. It’s changing at runtime. Swizzling is an example. And methods that are inherited from NSObject classes 1020 | 1021 | How compiler choses the method? 1022 | For value types it’s always static, for classes and protocols it’s static in the extension and dynamic in the initial implementation. For final classes it’s still static. Dynamic and @objc 1023 | Keywords make it Message dispatch. 1024 | 1025 | ### If a class is not inherited, what dispatch it has? 1026 | 1027 | ### Methods dispatch for protocols and their extensions 1028 | For protocol id depends on type that implements it - value or reference. For extension static dispatch is used, because it calculates in compile time how much memory to allocate there. 1029 | 1030 | 1031 | ## 68. What is "Hugging" and "Compression Resistance"? 1032 | Types of Constraints. 1033 | 1034 | Hugging - content does not want to grow 1035 | Compression Resistance - content does not want to shrink 1036 | 1037 | ## 69. Semaphore vs Mutex 1038 | 1039 | In swift Mutex is a lock, semaphore is a DispatchSemaphore 1040 | 1041 | Mutex - at any point of time, only one thread can work with the entire buffer. 1042 | Semaphore - allows the access to one resource to several threads, depending on some preset maximum. 1043 | 1044 | The Mutex is a locking mechanism - it blocks other threads from accessing some resource, and Semaphore is a signal mechanism which sends a signal when the resource is free and wait if it wants to access a resource. 1045 | 1046 | ## 70. DispatchSemaphore and DispatchGroup difference. 1047 | They are needed for different things. 1048 | DispatchSemaphore restricts the number of threads which can access some resource 1049 | DispatchGroup – launches a group of tasks and waits until they end. 1050 | 1051 | ## 71. What is UIView, what is CALayer, who is responsible for what? 1052 | 1053 | ## 72. What's happening if we fill a large array with values/references? 1054 | 1055 | If you create a very large array filled with reference types, allocating it on the stack can lead to a stack overflow, while allocating it on the heap can consume significant memory and may require proper memory management to prevent leaks 1056 | 1057 | ## 73. What's difference between as?, as!, as? 1058 | 1059 | ## 74. What is scene? 1060 | 1061 | # Behavioural: 1062 | 1063 | ## 1. Give me a short brief about yourself 1064 | I'm a software developer with N years of experience. For iOS I made some projects that included BLE, SwiftUI, network protocols (if you used them), etc. 1065 | 1066 | ## 2. Can you describe some of your projects and your role in these projects? 1067 | 1068 | 1069 | ## 3. How do you make branches? 1070 | For each feature create a separate branch, launch CI/CD, merge to develop. When release is coming, merge develop to master. 1071 | 1072 | ## 4. What was your biggest challenge as an iOS developer? 1073 | 1074 | Think about it, I'm sure you can find some accomplishment that you're proud of. 1075 | 1076 | ## 5. What can you bring to the company as an iOS developer? 1077 | 1078 | ## 6. Did you work with the team? Describe your usual working process 1079 | 1080 | ## 7. Do you have some questions about the company? 1081 | 1082 | Here it's better to ask about the project if they still didn't tell that, what is the earliest iOS version in the project, what management system they use, does they provide some budget for learning purposes (for example, paid courses compensation) 1083 | 1084 | 1085 | ## P.S.: Don't forget to call the interviewer by name, people like it 1086 | 1087 | ## A small note: if you made a mistake during your life coding then you completely failed the interview. 1088 | Companies and trainings always say that if you don't know how to solve a problem or answer a specific technical question, it doesn't mean you failed the interview. Actually it does, but they always deny it. 1089 | There is always another candidate who can handle the task without any problem, so if you fail the task, you fail the interview. So prepare harder, practice again and again. 1090 | 1091 | -------------------------------------------------------------------------------- /URLSessionMock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanMaxwell/iOS_interview_questions/5fbb831a487847286db063bb415569f06693e192/URLSessionMock.png -------------------------------------------------------------------------------- /appLifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanMaxwell/iOS_interview_questions/5fbb831a487847286db063bb415569f06693e192/appLifecycle.png -------------------------------------------------------------------------------- /viewControllerLifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanMaxwell/iOS_interview_questions/5fbb831a487847286db063bb415569f06693e192/viewControllerLifecycle.png --------------------------------------------------------------------------------