iOS Technical Interview Q&A Guide
iOS Technical Interview Q&A Guide
Architecture Patterns
CLEAN Architecture
Q: What is CLEAN Architecture? A: CLEAN Architecture is a software design philosophy created by Robert C. Martin that separates an application into layers with clear boundaries. The core principle is that dependencies point inward - outer layers depend on inner layers, never the reverse.
Q: What are the layers in CLEAN Architecture? A: From innermost to outermost:- Entities: Core business objects and logic
- Use Cases/Interactors: Application-specific business rules
- Interface Adapters: Presenters, ViewModels, Controllers
- Frameworks & Drivers: UI, Database, Network, External APIs
Q: Why use CLEAN Architecture? A: Benefits include testability (mock dependencies easily), maintainability (clear separation), flexibility (swap implementations), and independence from frameworks. It's ideal for large, complex applications with multiple developers.
Q: What are the disadvantages of CLEAN Architecture? A: More boilerplate code, steeper learning curve, more files to manage, and can be overkill for small applications or prototypes.
MVC (Model-View-Controller)
Q: What is MVC and how does it work in iOS? A: MVC separates app into three components: Model (data and logic), View (UI elements), and Controller (coordinates between Model and View). In iOS, UIViewController often becomes a "Massive View Controller" handling too many responsibilities.
Q: What is the Massive View Controller problem? A: View Controllers in iOS tend to accumulate too much code - handling view logic, business logic, network calls, and data transformation. This makes them hard to test, maintain, and reuse.
Q: How can you solve the Massive View Controller problem? A: Use patterns like MVVM, extract logic into separate classes, use child view controllers, create specialized managers (NetworkManager, DataManager), and use protocols for delegation.
MVVM (Model-View-ViewModel)
Q: What is MVVM? A: MVVM separates UI (View) from business logic using a ViewModel as an intermediary. The View observes ViewModel changes and updates automatically. The ViewModel contains presentation logic but knows nothing about the View.
Q: What are the benefits of MVVM over MVC? A: Better testability (ViewModel is independent of UIKit), clearer separation of concerns, reduced View Controller size, and easier to maintain. ViewModels are pure Swift classes that can be unit tested without UI.
Q: How does data binding work in MVVM? A: The View observes ViewModel properties. When ViewModel updates data, the View automatically refreshes. This can be implemented using Combine, RxSwift, property observers, closures, or SwiftUI's property wrappers.
Q: When should you use MVVM vs MVC? A: Use MVVM for complex UIs with significant business logic, when testability is crucial, or when using reactive programming. Use MVC for simple screens or when rapid prototyping.
VIPER (View-Interactor-Presenter-Entity-Router)
Q: What is VIPER Architecture? A: VIPER is a more granular architecture where each component has a single responsibility: View (displays UI), Interactor (business logic), Presenter (prepares data for display), Entity (data models), and Router (navigation logic).
Q: When would you use VIPER? A: For very large, complex applications with multiple developers where extreme modularity is needed. It's overkill for most apps due to the high amount of boilerplate.
Q: What's the difference between VIPER and CLEAN? A: VIPER is a specific implementation of CLEAN Architecture principles with more granular components. CLEAN is more flexible and has fewer mandatory components.
Coordinator Pattern
Q: What is the Coordinator pattern? A: A pattern that extracts navigation logic from View Controllers into separate Coordinator objects. Each Coordinator manages the flow of a specific feature or user journey.
Q: Why use Coordinators? A: Removes navigation responsibility from View Controllers, makes navigation logic reusable and testable, enables deep linking easily, and allows View Controllers to be more focused and reusable.
Q: How do Coordinators communicate with each other? A: Through delegation, protocols, closures, or by having parent coordinators manage child coordinators. Child coordinators notify parents when they're finished.
Dependency Injection
Q: What is Dependency Injection? A: A design pattern where objects receive their dependencies from external sources rather than creating them internally. This promotes loose coupling and makes code more testable.
Q: What are the types of Dependency Injection? A:
- Constructor Injection: Dependencies passed through initializer (most common in iOS)
- Property Injection: Dependencies set after initialization (useful for storyboards)
- Method Injection: Dependencies passed as method parameters
Q: Why is Dependency Injection important for testing? A: It allows you to inject mock objects during testing instead of real implementations. This lets you test components in isolation without requiring actual network calls, database access, or UI.
Q: What is a Dependency Injection Container? A: A centralized object responsible for creating and managing dependencies. It knows how to construct objects with their required dependencies and can manage singleton instances.
Q: What's the difference between Service Locator and Dependency Injection? A: Service Locator is an anti-pattern where objects fetch their own dependencies from a global registry. DI is better because dependencies are explicit, making code clearer and more testable.
Memory Management (ARC)
Q: What is ARC? A: Automatic Reference Counting is Swift's memory management system. It automatically tracks and manages app memory by counting references to class instances and deallocating them when the reference count reaches zero.
Q: What types does ARC apply to? A: Only reference types (classes). Value types (structs, enums) are copied, not reference counted.
Q: What is a strong reference? A: The default reference type that increases the reference count. As long as one strong reference exists, the object stays in memory.
Q: What is a weak reference? A: A reference that doesn't increase the reference count. When the referenced object is deallocated, the weak reference automatically becomes nil. Weak references must be optional variables.
Q: What is an unowned reference? A: Like weak, but assumes the reference will never be nil during its lifetime. Accessing a deallocated unowned reference causes a crash. Unowned references can be constants and non-optional.
Q: When do you use weak vs unowned? A: Use weak when the reference might become nil (like delegates). Use unowned when you're certain the reference will always exist while you need it (like a child object that can't outlive its parent).
Q: What is a retain cycle? A: When two objects hold strong references to each other, creating a reference loop. Neither can be deallocated because each keeps the other alive, causing a memory leak.
Q: How do you break a retain cycle? A: Use weak or unowned references for one side of the relationship. Common pattern: make delegate properties weak, use capture lists in closures.
Q: What is a capture list in closures? A: A list of references the closure should capture with specific ownership semantics, typically making self weak or unowned to prevent retain cycles.
Q: When do closures cause retain cycles? A: When a closure captures self strongly and the object also holds a strong reference to the closure (especially escaping closures stored as properties or passed to async operations).
Q: What is the deinit method? A: A special method called when an object is about to be deallocated. Used for cleanup tasks like invalidating timers, removing observers, or closing file handles.
Q: How do you debug memory leaks? A: Use Instruments (Leaks and Allocations), Xcode's Memory Graph Debugger, add deinit print statements, check for strong reference cycles, and look for purple warnings in the memory graph.
Q: What's the difference between a memory leak and a strong reference cycle? A: A strong reference cycle is a specific type of memory leak where two objects reference each other. Memory leaks can also occur from not invalidating timers, not removing observers, or retaining closures unnecessarily.
Grand Central Dispatch (GCD)
Q: What is GCD? A: Grand Central Dispatch is Apple's low-level API for managing concurrent operations using dispatch queues. It abstracts thread management and makes concurrent programming easier.
Q: What is a dispatch queue? A: A queue that manages the execution of tasks. Queues execute tasks either serially (one at a time) or concurrently (multiple simultaneously).
Q: What's the difference between serial and concurrent queues? A: Serial queues execute one task at a time in FIFO order. Concurrent queues can execute multiple tasks simultaneously, though they still dequeue in FIFO order.
Q: What is the main queue? A: A serial queue that runs on the main thread. All UI updates must happen on the main queue. Accessing the main queue from a background thread requires dispatching to it.
Q: What are global queues? A: System-provided concurrent queues with different Quality of Service levels. They're convenient for background work without creating custom queues.
Q: What is Quality of Service (QoS)? A: Priority levels for tasks: User Interactive (highest - UI), User Initiated (user waiting), Default, Utility (long-running with progress), Background (lowest - maintenance).
Q: What's the difference between sync and async? A: Async returns immediately and executes the task in the background. Sync blocks the current thread until the task completes. Never call sync on the current queue as it causes deadlock.
Q: What is a deadlock? A: When a thread waits for itself or creates a circular waiting dependency. Example: calling sync on the main queue from the main thread.
Q: What is a Dispatch Group? A: An object that allows you to track multiple tasks and get notified when they all complete. Useful for coordinating multiple async operations.
Q: What is a dispatch barrier? A: A task that executes exclusively on a concurrent queue. It waits for all previous tasks to complete, executes alone, then allows subsequent tasks. Used for thread-safe writes.
Q: When would you use a barrier? A: When implementing thread-safe collections or resources that allow concurrent reads but exclusive writes.
OperationQueue vs GCD
Q: What is OperationQueue? A: A higher-level API built on top of GCD that manages a queue of Operation objects. Provides more features than raw GCD queues.
Q: What are the advantages of OperationQueue over GCD? A: Dependencies between operations, easy cancellation, KVO-observable properties, operation priorities, max concurrent operations limit, and operations can be subclassed.
Q: When should you use GCD vs OperationQueue? A: Use GCD for simple async tasks and when performance is critical. Use OperationQueue when you need dependencies, cancellation, or complex task management.
Q: Can Operations have dependencies? A: Yes, you can specify that one operation must complete before another starts. This makes complex workflows easier to manage.
Q: How do you cancel an Operation? A: Call the cancel method. The operation must check its isCancelled property periodically and stop execution gracefully.
Swift Language Features
Optionals
Q: What are optionals? A: A type that can hold either a value or nil. They make null safety explicit in Swift, preventing null pointer crashes common in other languages.
Q: What's the difference between implicit and explicit optionals? A: Explicit optionals (Type?) must be unwrapped before use. Implicit optionals (Type!) automatically unwrap but crash if nil. Avoid implicit optionals except for IBOutlets.
Q: What are the ways to unwrap an optional? A: Optional binding (if let, guard let), optional chaining (?.), nil coalescing (??), force unwrapping (!), and optional pattern matching.
Q: When should you force unwrap? A: Rarely. Only when you're absolutely certain a value exists and a crash is acceptable. Better to use guard or if let.
Q: What is optional chaining? A: A way to call properties, methods, and subscripts on an optional that might be nil. If any link is nil, the whole chain fails gracefully and returns nil.
Q: What is the nil coalescing operator? A: The ?? operator provides a default value when an optional is nil. Cleaner than if-let when you just need a fallback value.
Value Types vs Reference Types
Q: What's the difference between value types and reference types? A: Value types (structs, enums) are copied when assigned or passed. Reference types (classes) are shared - assignments create a new reference to the same object.
Q: When should you use a struct vs a class? A: Use structs for simple data models without inheritance, thread-safe code, and when copying semantics make sense. Use classes for identity requirements, inheritance, or Objective-C interoperability.
Q: Are structs always better than classes? A: No. Classes are better for modeling shared state, when identity matters, for inheritance hierarchies, and when working with APIs requiring classes (like UIViewController).
Q: What is copy-on-write? A: An optimization where Swift collections (Array, Dictionary) share storage until modified. When you modify a shared collection, Swift creates a copy only then.
Q: Can structs have methods? A: Yes. Structs can have initializers, methods, properties, subscripts, and conform to protocols - almost everything classes can do except inheritance.
Protocols
Q: What is a protocol? A: A blueprint defining methods, properties, and requirements that conforming types must implement. Swift's version of interfaces.
Q: What is protocol-oriented programming? A: A paradigm emphasizing protocols and protocol extensions over inheritance. Preferred in Swift for its flexibility and composition capabilities.
Q: What are protocol extensions? A: Extensions that provide default implementations for protocol requirements. Types can use defaults or override with custom implementations.
Q: What's the difference between class and protocol inheritance? A: Classes support single inheritance. Types can conform to multiple protocols. Protocols enable composition and are more flexible.
Q: What are associated types in protocols? A: Placeholder types defined in protocols. The actual type is specified when a type conforms to the protocol. Like generics for protocols.
Q: What is a protocol witness table? A: The mechanism Swift uses to implement dynamic dispatch for protocols. Maps protocol requirements to actual implementations.
Closures
Q: What is a closure? A: A self-contained block of functionality that can be passed around. Closures can capture and store references to variables from their surrounding context.
Q: What's the difference between escaping and non-escaping closures? A: Non-escaping closures execute before the function returns. Escaping closures can execute after the function returns (async operations). Escaping closures must explicitly capture self.
Q: What is a capture list? A: Syntax for specifying how closures should capture variables from their environment, typically to prevent retain cycles by using weak or unowned.
Q: What are trailing closures? A: Syntactic sugar allowing closure arguments to be written outside function parentheses, making code more readable when the closure is the last parameter.
Q: What is autoclosure? A: An attribute that automatically wraps an expression in a closure. Used for lazy evaluation - the expression isn't evaluated until the closure is called.
Property Wrappers
Q: What are property wrappers? A: A feature that lets you define reusable logic for getting and setting property values. Common examples: @State, @Published, @AppStorage.
Q: What are some built-in property wrappers in SwiftUI? A: @State (view-local state), @Binding (two-way binding), @ObservedObject (external observable), @StateObject (owned observable), @EnvironmentObject (dependency injection).
Q: How do you create a custom property wrapper? A: Define a struct or class with @propertyWrapper attribute and implement wrappedValue property. Can include projectedValue for additional functionality.
Q: What's the difference between @State and @StateObject? A: @State is for value types and simple data. @StateObject is for reference types that conform to ObservableObject. StateObject owns and manages the object's lifetime.
SwiftUI vs UIKit
Q: What are the main differences between SwiftUI and UIKit? A: SwiftUI is declarative (describe what you want), uses value types (structs), has automatic state management, and less boilerplate. UIKit is imperative (describe how to build), uses classes, and requires manual state synchronization.
Q: What is the declarative paradigm? A: You declare what the UI should look like for each state. The framework figures out how to update the UI when state changes. Opposite of imperative where you manually update views.
Q: How does data flow work in SwiftUI? A: Single source of truth pattern. Data flows down through property wrappers like @State, @Binding, @ObservedObject. Views automatically update when data changes.
Q: Can you mix SwiftUI and UIKit? A: Yes. Use UIViewRepresentable to wrap UIKit views in SwiftUI, or UIHostingController to embed SwiftUI in UIKit. Useful for gradual migration.
Q: What is @State in SwiftUI? A: A property wrapper for view-local state. When state changes, SwiftUI automatically recomputes the view body and updates the UI.
Q: What is @Binding? A: A property wrapper that creates a two-way connection to state owned by another view. Changes flow both directions.
Q: What is @ObservedObject vs @StateObject? A: ObservedObject is for externally created objects. StateObject owns and manages the object lifecycle. Use StateObject for objects created in the view.
Q: When should you use SwiftUI vs UIKit? A: SwiftUI for new projects, simple to medium complexity, iOS 13+ target, rapid prototyping. UIKit for complex custom UIs, precise control, backward compatibility, or when SwiftUI lacks features.
Networking
Q: What is URLSession? A: Apple's API for network requests. Handles HTTP(S) communication, downloads, uploads, background transfers, and authentication.
Q: What are the types of URLSession tasks? A: DataTask (simple data requests), DownloadTask (file downloads with progress), UploadTask (file uploads), StreamTask (TCP/IP connections), and WebSocketTask (WebSocket connections).
Q: What's the difference between URLSession.shared and custom sessions? A: Shared session has default configuration. Custom sessions allow custom cache policies, timeouts, cookie handling, and background transfers.
Q: How do you handle network errors? A: Check for Error in completion handler, validate HTTP status codes, check response.statusCode, handle timeouts, and implement retry logic with exponential backoff.
Q: What is Codable? A: Protocol combining Encodable and Decodable for easy JSON serialization/deserialization. Automatically synthesized for types with Codable properties.
Q: How do you handle authentication in URLSession? A: Implement URLSessionDelegate methods, add Authorization headers, use URLCredential, or implement custom authentication challenges.
Q: What is Certificate Pinning? A: Security technique validating server certificates against known certificates to prevent man-in-the-middle attacks. Validates the exact certificate or public key.
Q: What's the difference between synchronous and asynchronous networking? A: Synchronous blocks the thread until complete (never use on main thread). Asynchronous uses callbacks/async-await and doesn't block. Always use async for networking.
Data Persistence
Q: What are the data persistence options in iOS? A: UserDefaults (small key-value data), Keychain (secure credentials), File System (documents, caches), Core Data (object graph), SQLite (relational database), Realm (mobile database), and CloudKit (iCloud sync).
Q: When should you use UserDefaults? A: For small amounts of user preferences, settings, and simple key-value data. Not for sensitive data or large datasets.
Q: What is the Keychain? A: Secure storage for sensitive data like passwords, tokens, and certificates. Data is encrypted and survives app deletion.
Q: What is Core Data? A: Apple's object graph and persistence framework. Manages model objects with relationships, provides change tracking, undo/redo, and background processing.
Q: Is Core Data a database? A: No, it's an object graph management and persistence framework. It can use SQLite as a backing store, but also supports other stores.
Q: What is NSManagedObjectContext? A: The scratchpad where you work with Core Data objects. Tracks changes and manages object lifecycle.
Q: What is a fetch request? A: The way to query Core Data. Specifies what objects to fetch, with optional predicates, sort descriptors, and fetch limits.
Q: What are the differences between UserDefaults and Keychain? A: UserDefaults is for non-sensitive preference data, unencrypted, simple API. Keychain is for sensitive data, encrypted, more complex API, persists across app deletions.
App Lifecycle
Q: What are the app lifecycle states? A: Not Running, Inactive, Active, Background, and Suspended. Apps transition between these based on user actions and system events.
Q: What is the difference between Inactive and Active? A: Active means the app is in the foreground and receiving events. Inactive is transitional - foreground but not receiving events (like during a phone call overlay).
Q: When does applicationDidEnterBackground get called? A: When the app moves from foreground to background. You have limited time (typically seconds) to save state and release resources.
Q: What is Scene-based lifecycle (iOS 13+)? A: New lifecycle model supporting multiple windows. Scenes represent UI instances. SceneDelegate handles scene-specific lifecycle, AppDelegate handles app-level events.
Q: What happens when the app is suspended? A: The app is in memory but not executing code. System can terminate suspended apps without notice to free memory.
Q: How much time do you have in background? A: Typically 30 seconds for cleanup tasks. For longer operations, request background execution time using beginBackgroundTask.
View Lifecycle (UIKit)
Q: What is the UIViewController lifecycle order? A: init → loadView → viewDidLoad → viewWillAppear → viewWillLayoutSubviews → viewDidLayoutSubviews → viewDidAppear → viewWillDisappear → viewDidDisappear → deinit
Q: When should you use viewDidLoad vs viewWillAppear? A: viewDidLoad: One-time setup (called once). viewWillAppear: Updates before every appearance (called each time view appears).
Q: What's the difference between viewDidLoad and loadView? A: loadView creates the view hierarchy (rarely overridden unless programmatic UI without Interface Builder). viewDidLoad is called after views are loaded for additional setup.
Q: Why shouldn't you update UI in viewDidLoad? A: Views are loaded but not laid out yet. Frame sizes may be incorrect. Use viewDidLayoutSubviews or viewWillAppear for layout-dependent updates.
Q: When is viewWillLayoutSubviews called? A: Before view's bounds change and before subviews are laid out. Called multiple times as layout changes (rotation, size changes).
Auto Layout
Q: What is Auto Layout? A: A constraint-based layout system that defines relationships between views. Views position and size themselves based on constraints relative to other views or their container.
Q: What are constraints? A: Rules defining view position and size using mathematical relationships. Each constraint has items, attributes, relationships, multipliers, and constants.
Q: What is intrinsic content size? A: The natural size a view wants to be based on its content. UILabel's intrinsic size is determined by its text. Used for content-driven layouts.
Q: What are constraint priorities? A: Values from 1-1000 indicating how important constraints are. Required (1000) must be satisfied. Lower priorities are satisfied if possible. Used to resolve conflicts.
Q: What is content hugging vs compression resistance? A: Content hugging resists growing larger than intrinsic size. Compression resistance resists shrinking smaller than intrinsic size. Both have priorities.
Q: What causes Auto Layout conflicts? A: Ambiguous layouts (insufficient constraints), conflicting constraints (mathematically impossible requirements), or missing constraints for some axis.
Q: How do you debug Auto Layout issues? A: Check console for constraint conflict messages, use view debugger, add identifiers to constraints, use breakpoints on UIViewAlertForUnsatisfiableConstraints, test on multiple device sizes.
Q: What's the difference between frame and bounds? A: Frame is position and size relative to superview. Bounds is position and size in own coordinate system (origin usually 0,0). Use bounds for internal layout, frame for positioning.
Delegates vs Notifications vs KVO
Q: When should you use delegates? A: For one-to-one communication between specific objects. Common for callbacks from views to controllers. Clean, type-safe, and compiler-checked.
Q: When should you use notifications? A: For one-to-many communication where multiple objects need to know about events. Good for loosely coupled communication across the app.
Q: What are the disadvantages of NotificationCenter? A: Not type-safe, easy to forget to remove observers (causing crashes or leaks), harder to trace flow, and no compiler checking.
Q: What is KVO (Key-Value Observing)? A: Mechanism to observe property changes on objects. The observer is notified when the observed property changes.
Q: What are the problems with KVO? A: Objective-C based, requires inheritance from NSObject, stringly-typed (property names as strings), easy to crash if not removed properly, and verbose setup.
Q: What are modern alternatives to KVO? A: Combine framework (Publishers), property observers (willSet/didSet), closures/callbacks, and reactive frameworks like RxSwift.
Combine Framework
Q: What is Combine? A: Apple's reactive programming framework for handling asynchronous events. Processes values over time using publishers and subscribers.
Q: What is a Publisher? A: An object that emits values over time. Can emit zero or more values and eventually completes successfully or with an error.
Q: What is a Subscriber? A: An object that receives values from a publisher. Requests values and receives them asynchronously.
Q: What are Operators? A: Methods on publishers that transform, filter, or combine values. Examples: map, filter, flatMap, combineLatest, debounce, throttle.
Q: What's the difference between debounce and throttle? A: Debounce waits for a pause in events (good for search as you type). Throttle limits event frequency (good for button taps or scroll events).
Q: What is @Published? A: Property wrapper that creates a publisher for a property. When the property changes, subscribers are notified automatically.
Q: When should you use Combine? A: For reactive data flows, chaining async operations, handling multiple data sources, form validation, and network + UI coordination.
Testing
Q: What are the types of tests in iOS? A: Unit tests (individual components), Integration tests (component interactions), UI tests (user interface automation), and Performance tests (measuring execution time/memory).
Q: What makes code testable? A: Dependency injection, protocol-oriented design, pure functions (no side effects), small focused classes/functions, and separation of concerns.
Q: What is test-driven development (TDD)? A: Writing tests before implementation. Write failing test → write minimal code to pass → refactor. Results in better design and complete test coverage.
Q: What should you test in view models? A: Business logic, state transitions, error handling, data transformations, and side effects. Mock dependencies to isolate what you're testing.
Q: What should you NOT test? A: Framework code (Apple's code), third-party libraries (assume they work), trivial getters/setters, and UI layout details.
Q: What is code coverage? A: Percentage of code executed by tests. Higher is generally better but 100% isn't always necessary or practical. Focus on critical business logic.
Q: What are mocks vs stubs? A: Stubs provide predetermined responses. Mocks verify interactions (method calls, parameters). Both are test doubles replacing real dependencies.
Q: How do you test asynchronous code? A: Use XCTestExpectation, wait for expectations to fulfill, or use async/await with async test functions in modern Swift.
Q: What is snapshot testing? A: Recording and comparing UI screenshots to detect unintended visual changes. Useful for ensuring UI consistency across changes.
Comments
Post a Comment