iOS interview questions and answers for 2025
Interview Questions For Freshers and Intermediate Levels
What is the difference between var and let in Swift?
var
is used to declare variables whose values can change (mutable).let
is used to declare constants whose values cannot be changed once assigned (immutable).Example:
var name = "John" // mutable
name = "Jane" // allowed
let age = 25 // immutable
// age = 26 // not allowed, compile-time error
What is optional chaining and how is it used in Swift?
Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil
. If the optional is nil
, the call returns nil
without causing a runtime error; otherwise, it unwraps and proceeds.
Example:
struct Person {
var dog: Dog?
}
struct Dog {
var name: String
}
let person = Person(dog: Dog(name: "Rex"))
print(person.dog?.name ?? "Dog is nil") // "Rex"
If person.dog was nil, person.dog?.name would simply return nil.
What is ARC (Automatic Reference Counting)?
ARC is a memory management mechanism in Swift (and Objective-C) that automatically keeps track of how many references point to each class instance.
When there are no more references (strong references) to an object, ARC frees it from memory. This eliminates the need for manual memory management most of the time.
How would you use a completion handler in Swift?
A completion handler is a callback function passed as an argument to another function. It executes after a task completes (e.g., a network request). This helps with asynchronous operations.
Example:
func fetchData(completion: @escaping (Data?) -> Void) {
// Simulate asynchronous task
DispatchQueue.global().async {
let data = Data()
completion(data)
}
}
Here, the completion handler is called once data is fetched.
What is the difference between Struct and Class in Swift?
- Structs are value types; they are copied on assignment or passing.
- Classes are reference types; multiple variables can refer to the same instance. Classes support inheritance, while structs do not.
What is a protocol and how do you define one?
A protocol defines a blueprint of methods, properties, and other requirements that a class, struct, or enum can adopt.
Example:
protocol Greetable {
var greeting: String { get }
func greet()
}
struct Greeter: Greetable {
let greeting: String
func greet() {
print(greeting)
}
}
What are extensions in Swift?
Extensions add new functionality to an existing class, struct, enum, or protocol type without modifying the original source code. They can add computed properties, instance methods, type methods, and more.
Example:
extension String {
var reversedString: String {
return String(self.reversed())
}
}
What is the difference between synchronous and asynchronous tasks?
Async tasks are added to the queue and execution is immediately continued without waiting till the async task is finished – async task will be executed at some in future.
Sync tasks are added to the queue and execution will be continued after thing tasks is finished.
Explain MVC architecture in iOS.
Model-View-Controller (MVC):
- Model: Manages the data and business logic.
- View: Handles the UI and presentation.
- Controller: Mediates between Model and View, handling updates and user input. This helps separate concerns and maintain cleaner code.
When would you use guard/guard let vs if/if let in Swift?
Best practices:
if/if let
statements are used to unwrap optional or checks inside the scope that are not influencing on general execution flow of a current scopeguard/guard let
statements are used to explicitly check the conditions to understand if the execution should be continued. If condition inguard/guard let
statement fails in most cases it means that the current scope should be exited.
What is Codable in Swift and how do you use it?
Codable
is a protocol that combines Encodable
and Decodable
. It allows easy encoding/decoding of custom data types into/from formats like JSON.
Example:
struct User: Codable {
let name: String
let age: Int
}
// Encoding
let user = User(name: "John", age: 25)
if let encoded = try? JSONEncoder().encode(user) {
// Decoding
let decodedUser = try? JSONDecoder().decode(User.self, from: encoded)
}
How do you handle errors in Swift?
Swift uses the throw
, try
, and catch
keywords to handle errors. Functions can declare that they throw errors, which must be handled by callers.
Example:
enum DataError: Error {
case noData
}
func loadData() throws -> String {
throw DataError.noData
}
do {
let data = try loadData()
} catch {
print("Error: \(error)")
}
What is a lazy stored property?
A lazy
stored property is not calculated until the first time it’s accessed. It’s useful for delaying costly initializations until they’re actually needed.
Example:
class DataManager {
lazy var data = expensiveDataLoad() // `data` is only loaded when first accessed
func expensiveDataLoad() -> [String] { return ["Item1","Item2"] }
}
Explain URLSession and its usage.
URLSession
is a framework/API that provides a set of classes and methods for configuring and managing network sessions. It gives a possibility to fetch data from a server, upload and download media and content files, and handles WebSocket communication.
Example:
let url = URL(string: "https://api.example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
// Handle response
}
task.resume()
What is Grand Central Dispatch (GCD)?
GCD is an API in iOS for managing concurrent operations. It allows you to dispatch tasks to different queues (main, global, custom) and handle parallelism easily.
Example:
DispatchQueue.global().async {
// Background task
DispatchQueue.main.async {
// Update UI on main thread
}
}
How do you localize an iOS application?
Localization involves providing different versions of your app’s text and resources for different languages and regions.
You use Localizable.strings files, .stringsdict, and setting the development language. In code, you use NSLocalizedString(key, comment: “”) or String(localized: “”, comment: “”)
Explain what Autolayout is.
Autolayout is a system that lets you define rules (constraints) for how views are positioned and sized relative to each other and their container.
It dynamically adjusts layouts for different screen sizes and orientations.
What is the difference between frame and bounds of a UIView?
frame
: The view’s location and size in the coordinate system of its superview.bounds
: The view’s location and size in its own coordinate space.
How do you trigger layout updates in iOS?
You can call methods like setNeedsLayout() or layoutIfNeeded() on views. setNeedsLayout() marks the view as needing a layout update, and layoutIfNeeded() forces an immediate layout pass if necessary.
What is a UITableView and how is it used?
UITableView
is a UIKit component that displays a list of cells in a single column, scrolling vertically. You provide data via its dataSource
and handle user interaction via its delegate
.
Example (basic):
class ViewController: UIViewController, UITableViewDataSource {
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int { return 10 }
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Row \(indexPath.row)"
return cell
}
}
What is a UICollectionView and
how does it differ from UITableView?
A UICollectionView is similar to UITableView but provides a more flexible layout system. Instead of a single column list, it can arrange items in a grid or custom layouts.
It uses a UICollectionViewLayout object to define how items are laid out.
What is the purpose of AppDelegate?
AppDelegate (or UIApplicationDelegate) responds to app-level events such as app launching, entering background, receiving notifications, etc. It’s the central point for handling global application states.
How do you store user preferences in iOS?
You can use UserDefaults to store small pieces of user-related data like settings or preferences.
Example:
UserDefaults.standard.set(true, forKey: "isLoggedIn")
let loggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn")
Explain the concept of Core Data.
Core Data is Apple’s framework for object graph management and persistence. It lets you model data using entities and attributes, and store them in a SQLite database or in-memory behind the scenes.
It simplifies data management, relationships, and querying.
What are @IBOutlet and @IBAction?
@IBOutlet
: A reference to a UI element in a storyboard or XIB file, allowing code to access and manipulate it.@IBAction
: A method triggered by a UI element event, like a button press, connecting UI events to code.
What is a Navigation Controller?
A UINavigationController manages a stack of view controllers. It provides navigation between screens via a navigation bar and back button.
You push new view controllers onto the stack and pop them to go back.
How do you handle memory warnings in iOS?
In modern iOS development, explicit memory warnings are less common. When they occur, UIApplicationDelegate’s applicationDidReceiveMemoryWarning() or a view controller’s didReceiveMemoryWarning() might be called. You should release any unneeded resources or cached data.
What is the difference between init() and convenience init() in Swift?
init()
: A designated initializer that fully initializes all properties of a class.convenience init()
: A secondary initializer that must call another designated initializer. Convenience initializers often provide additional configuration options or simplified initialization paths.
Discuss handling of concurrency with async/await in Swift.
async/await provides a structured concurrency model. async functions allow suspending execution until async tasks finish, making code more readable:
func fetchData() async -> Data {
let (data, _) = try! await URLSession.shared.data(from: URL(string: "https://example.com")!)
return data
}
This avoids callback pyramids and makes asynchronous code more synchronous-looking.
How to prevent retain cycles in closures and delegates?
- Use
[weak self]
in closure capture lists to avoid strong reference cycles. - Delegates should be
weak
references.Example:
class MyClass {
var callback: (() -> Void)?
func setup() {
callback = { [weak self] in
self?.doSomething()
}
}
}
Explain the difference between synchronous, asynchronous, and concurrent operations.
- Synchronous: Tasks run one after another, waiting for each to finish.
- Asynchronous: Tasks can begin and return immediately, freeing the caller to do other work. The task finishes later.
- Concurrent: Multiple tasks run at the same time (in parallel if hardware allows).
Interview Questions For Experienced Levels
Explain the concept and use of DispatchWorkItem in GCD.
DispatchWorkItem
allows you to create a block of code you can dispatch to a queue, cancel before execution, or notify when complete. This provides more control over asynchronous tasks.
Example:
let workItem = DispatchWorkItem {
// Heavy computation
}
DispatchQueue.global().async(execute: workItem)
// Later you can cancel if needed
workItem.cancel()
How does Swift’s memory management differ from Objective-C’s?
- Swift uses ARC for both reference types and provides automatic memory management for most scenarios.
- Swift enforces safe memory practices (e.g., no dangling pointers) and provides options/guarding to prevent nil references.
- Objective-C uses ARC but still relies on pointers and has more legacy memory management patterns (weak references with special qualifiers, etc.).
What are the performance considerations when using Core Data?
- Use
NSFetchedResultsController
for efficiently managing large data sets. - Avoid fetching all data at once; use predicates and fetch limits.
- Batch updates and batch deletes reduce memory usage and improve performance.
- Consider indexing frequently queried attributes.
Explain how Operations and OperationQueues differ from GCD.
OperationQueues/Operation: Higher-level abstraction on top of GCD. Operations can be paused, canceled, have dependencies, and provide more control over concurrency and execution states.
What are escaping and non-escaping closures in Swift?
- Non-escaping closures: The closure is guaranteed to be executed before the function returns. No need for
@escaping
. - Escaping closures: The closure may be stored and executed later after the function returns. Must be marked with
@escaping
.
Explain what the resultBuilder feature in Swift does.
A result builder (e.g., @resultBuilder or @ViewBuilder in SwiftUI) is a feature that lets you build complex data structures from a sequence of statements. It transforms imperative-looking code into a declarative structure. Commonly used in SwiftUI to build UI hierarchies.
Describe the difference between Main and Global queues in GCD.
- Main queue: Serialized queue that runs on the main thread, used for UI updates.
- Global queues: Concurrent queues for background work. They come in different priorities:
.userInteractive
,.userInitiated
,.utility
, and.background
.
How would you implement dependency injection in Swift?
Use initializers or property injection to provide dependencies. Protocols can define what a dependency looks like. Constructor injection is common:
Example:
protocol DataService {
func fetchData() -> [String]
}
class MyViewModel {
private let service: DataService
init(service: DataService) {
self.service = service
}
}
Compare MVP, MVVM, and VIPER architectures.
- MVP: Model-View-Presenter separates business logic from UI. Presenter updates the View.
- MVVM: Model-View-ViewModel introduces a ViewModel that binds data to the View, often using data binding.
- VIPER: View-Interactor-Presenter-Entity-Router splits responsibilities into layers, aiming for a very modular and testable architecture.
How to optimize table view performance?
- Use reuse identifiers and dequeue reusable cells.
- Avoid complex layouts; consider pre-sizing or using Auto Layout efficiently.
- Use cell prefetching.
- Offload heavy tasks off the main thread, such as image loading.
Explain URLSession configuration and how to use it for caching and custom headers.
URLSession can be configured with URLSessionConfiguration. For caching:
let config = URLSessionConfiguration.default
config.requestCachePolicy = .returnCacheDataElseLoad
// custom headers
config.httpAdditionalHeaders = ["Authorization": "Bearer xyz"]
let session = URLSession(configuration: config)
This allows customizing timeouts, caching policies, headers, and more.
How do you implement offline caching for network requests in iOS?
- Use
URLCache
with appropriate cache policies. - Store JSON responses or other data in Core Data or local database.
- Use
NSKeyedArchiver
/Codable
to save objects to disk. - Implement a strategy to determine when to serve cached data vs. fresh data.
What are property wrappers in Swift and give an example?
Property wrappers allow you to define reusable logic for getter/setter and apply it to properties.
Example:
@propertyWrapper
struct Capitalized {
private var value: String
init(wrappedValue: String) {
self.value = wrappedValue.capitalized
}
var wrappedValue: String {
get { value }
set { value = newValue.capitalized }
}
}
struct User {
@Capitalized var name: String
}
let user = User(name: "john")
print(user.name) // "John"
What is the difference between NSLock, DispatchSemaphore,
and DispatchGroup?
- NSLock: A mutex lock for critical sections.
- DispatchSemaphore: Controls access to a resource with a given number of permits.
- DispatchGroup: Allows grouping of multiple tasks and notifying when all have completed.
Discuss testing strategies for iOS apps
- Unit Testing: Test individual components (business logic) using
XCTest
. - UI Testing: Automate UI interactions and verify results using
XCUITest
. - Snapshot Testing: Compare rendered UI to a reference image.
- Mocking & Dependency Injection: Helps isolate code and test behavior under controlled conditions.
How do you handle migration in Core Data?
Use Core Data’s migration system to move from one data model version to another. Lightweight migrations can be done automatically by setting the correct options when loading the persistent store.
For complex migrations, create a mapping model or use a custom migration policy.
Explain KVC and KVO in Swift.
- Key-Value Coding (KVC): Accessing object properties using strings (keys), typically
value(forKey:)
andsetValue(_:forKey:)
. - Key-Value Observing (KVO): Observing changes to a property value. Allows objects to be notified when a specific property changes.
When would you consider using SwiftUI over UIKit?
SwiftUI is used for building declarative UIs, providing a more modern approach to UI development, better code previews, and seamless integration with new Apple platforms.
Consider SwiftUI for new projects or rapid UI development. UIKit still excels in complex, legacy projects or when needing lower-level control.
How do you implement push notifications and handle background updates?
- Register for notifications with
UNUserNotificationCenter
. - Implement
UNUserNotificationCenterDelegate
methods to handle incoming notifications. - Use background modes in the app’s capabilities to update data silently.
- Implement
application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
to handle background updates.
Describe how you would use Instruments to profile an iOS app.
- Time Profiler: Measure CPU usage and identify performance bottlenecks.
- Allocations: Track memory usage and detect leaks.
- Leaks & Zombies: Identify memory leaks and over-released objects.
- Network: Monitor network requests. Run the app through Instruments, record a session, and analyze the data to optimize performance.
What are Combine publishers and subscribers?
Combine
is Apple’s reactive framework.
- Publishers: Emit values over time. Examples:
URLSession.DataTaskPublisher
,Just
,PassthroughSubject
. - Subscribers: Receive and handle emitted values. You chain publishers and operators to transform data, and subscribers handle the final output.
How would you implement Secure Coding and Keychain storage?
- Use
Keychain
for sensitive data (passwords, tokens). Apple providesKeychain Services
API. - Use
SecItemAdd
,SecItemCopyMatching
,SecItemUpdate
, andSecItemDelete
. - Implement
Codable
for secure coding and ensure data at rest is encrypted if needed.
Explain diffable data sources.
Diffable data sources were introduced to simplify UI updates. They use a snapshot of data to smoothly animate changes in collection/table views.
Instead of manually inserting/deleting rows, you apply a snapshot that calculates changes automatically.
Discuss the role of SceneDelegate.
Introduced in iOS 13, UISceneDelegate
manages UI scenes in multi-window environments (e.g., iPad). Each scene can have its own lifecycle, state restoration, and UI independent of others.
How do you ensure thread-safety in Swift code?
- Use serial queues for tasks that must not run concurrently.
- Use locks (
NSLock
), semaphores, or dispatch barriers for critical sections. - Make mutable state isolated to a single queue.
- Use atomics or
@Sendable
closures with Swift’s concurrency features.
How do you implement custom animations using
UIViewPropertyAnimator?
UIViewPropertyAnimator
provides fine-grained control over animations, allowing you to pause, resume, and scrub through animations.
Example:
let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeInOut) {
view.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)
}
animator.startAnimation()
// Later
animator.pauseAnimation()
animator.fractionComplete = 0.5 // jump to half
animator.continueAnimation(withTimingParameters: nil, durationFactor: 1.0)
Explain the difference between weak and unowned references in Swift.
- Both
weak
andunowned
references are not increasing the retain count weak
references are used when the referenced object can becomenil
at some point.weak
references are always optional and automatically set tonil
when the object is deallocated.unowned
references are used when the referenced object is never expected to benil
once initialized. Usingunowned
is a promise that the reference will always point to a valid object. If the object is deallocated and accessed, it leads to a runtime crash.
Senior-level iOS coding interview tasks
Create a SwiftUI View with a Button and Label
Possible solution:
import SwiftUI
struct ContentView: View {
@State private var message = "Hello, Lemon!"
var body: some View {
VStack {
Text(message)
.font(.title)
Button("Tap Me") {
message = "Button Pressed!"
}
.padding()
}
}
}
Fetch and Decode JSON Using Async/Await
Possible solution:
import Foundation
struct User: Codable {
let id: Int
let name: String
}
func fetchUsers() async throws -> [User] {
let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([User].self, from: data)
}
do {
let users = try await fetchUsers()
print(users)
} catch {
print("Failed to fetch users:", error)
}
Filter a List Using Combine
Possible solution:
import Combine
let names = ["Alice", "Bob", "Charlie", "David", "Eve"]
let searchPublisher = PassthroughSubject<String, Never>()
var cancellable = searchPublisher
.map { query in
names.filter { $0.lowercased().contains(query.lowercased()) }
}
.sink { filteredNames in
print("Filtered Names:", filteredNames)
}
searchPublisher.send("a") // Filters names containing "a"
searchPublisher.send("e") // Filters names containing "e"
Store and Retrieve Data Using UserDefaults
Possible solution:
import Foundation
UserDefaults.standard.set("Hello, Lemon!", forKey: "savedMessage")
let message = UserDefaults.standard.string(forKey: "savedMessage") ?? "No message found"
print(message)
Create and Use a Timer
Possible solution:
import Foundation
var counter = 0
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
counter += 1
print("Counter:", counter)
if counter == 5 {
timer.invalidate() // Stop after 5 seconds
}
}
Detect Device Orientation Changes (Simulated)
Possible solution:
import UIKit
func checkOrientation() {
let orientation = UIDevice.current.orientation
switch orientation {
case .portrait:
print("Portrait")
case .landscapeLeft, .landscapeRight:
print("Landscape")
default:
print("Unknown orientation") // Fallback if execution is in Playground
}
}
checkOrientation()
Implement a generic stack data structure with push, pop, and peek operations.
Possible solution:
struct LemonStack {
private var elements: [T] = []
mutating func push(_ item: T) {
elements.append(item)
}
mutating func pop() -> T? {
return elements.popLast()
}
func peek() -> T? {
return elements.last
}
}
var stack = LemonStack()
stack.push(1)
stack.push(2)
print(stack.pop() ?? "Stack is empty") // Prints 2
print(stack.peek() ?? "Stack is empty") // Prints 1
Implement a Simple Observer Pattern
Possible solution:
import Foundation
class LemonObservable {
private var observers = [() -> Void]()
func addObserver(_ observer: @escaping () -> Void) {
observers.append(observer)
}
func notifyObservers() {
observers.forEach { $0() }
}
}
let observable = LemonObservable()
observable.addObserver {
print("Observer 1 Notified")
}
observable.addObserver {
print("Observer 2 Notified")
}
observable.notifyObservers()
Create a Simple Async Function with Delayed Execution
Possible solution:
import Foundation
let delayTime: UInt64 = 3_000_000_000 // In nanoseconds, equals 3 seconds
func delayedTask() async {
print("Task started")
try? await Task.sleep(nanoseconds: delayTime)
print("Task completed after delay")
}
Task {
await delayedTask()
}
Use Gesture Recognizers in a UIView (UIKit)
Possible solution:
import UIKit
class LemonGestureView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .white
let tap = UITapGestureRecognizer(target: self,
action: #selector(handleTap))
self.addGestureRecognizer(tap)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func handleTap() {
self.backgroundColor = self.backgroundColor == .white ? .blue : .white
print("Tapped! Background changed")
}
}
let view = LemonGestureView(frame: CGRect(x: 0.0,
y: 0.0,
width: 300.0,
height: 300.0))
iOS Developer hiring resources
Our clients
Popular iOS Development questions
What security measures should be implemented in iOS Apps?
Security measures in iOS Apps may include some built-in Apple security frameworks, which can be employed to store sensitive data in keychains or implement SSL/TLS for secure data transmission. The developers should also take biometric authentication like Face ID/Touch ID; data encryption in rest and in transit are other important things for users. Some of the security measures one can follow to provide security in their iOS Apps are regular security audits, code obfuscation, and following Apple’s best practices in coding securely to protect the app from vulnerabilities and definitely ensure privacy regulation compliance.
What are the best practices for optimizing iOS App performance?
Performance optimization of an iOS App includes efficient memory management, reduction of unnecessary background tasks, and optimization of graphics and animation. In finding performance bottlenecks and memory leaks, Instruments should be used-a profiling tool in Xcode. Developers can do some more performance enhancements by minimizing heavy resources like large-sized images and also keep tasks running asynchronously. Testing on a regular basis on different devices ensures that the application works on all types of different hardware.
Will AI replace iOS Developers?
AI will not totally replace iOS Developers but complement them by automating routine tasks, optimizing codes, and much more. It will still require a person with creativity and expertise to design and develop an app, refine it, and make it comprehensive for projects that are complex and innovative. AI is a productivity enhancer and not a replacement for Developers themselves.
Is Python used in iOS Development?
Python is not used for iOS Development in general. The main programming languages for iOS Apps include Swift and Objective-C. While it’s possible to use Python in scripting, prototyping, or with such frameworks as Kivy, it’s not the conventional language to create iOS Applications.
Is iOS coded in C++?
iOS itself is not coded in C++, but it is possible to use C++ while developing for iOS, especially in the case where one needs to implement some performance-critical part or wants to integrate some pre-existing code written in C++. The core of iOS and most iOS applications are usually written in higher-order languages such as Swift and Objective-C, but languages like C and C++ can also be used in lower levels or libraries of an iOS project.
What programming language is used for iOS Development?
Main iOS Development programming languages include Swift and Objective-C. Swift is a modern, and newer language, developed by Apple to create iOS, macOS, and other Apple platform apps. At the same time, Objective-C is an older one, which was used for creating iOS initially. Most new development in iOS is written in Swift because it is easier to use and more efficient.
What is iOS Development?
iOS Development is the development of applications running on Apple devices: iPhones, iPads, and iPod Touch alike. They use a similar operating system, known as iOS. It therefore includes using languages such as Swift or Objective-C, and using development tools like Xcode in designing, coding, and deploying applications according to guidelines and standards laid down by Apple.
Interview Questions by role
Interview Questions by skill
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions
Interview Questions