This is an update of my two-year-old blog post on iOS interview questions. I revised it after doing extensive research while working on my book on the topic: The iOS Interview Guide.
When you’re prepping for your technical iOS interview, it is important to understand what topics you could be asked about and what is expected from a seasoned iOS developer. This is a collection of questions a lot of Silicon Valley companies use to gauge the level of seniority in an iOS candidate. The questions go over various aspects of iOS development and aim to touch upon a broad understanding of the platform. Senior developers are expected to be able to ship full iOS products from start to finish, after all. This is by no means an exhaustive list, but it can help you prepare for your upcoming technical iOS interview.
- What was the latest version of iOS you worked with? What do you like about it and why?
- What is an iOS application and where does your code fit into it?
- What features of Swift do you like or dislike? Why?
- How is memory management handled on iOS?
- What do you know about singletons? Where would you use one and where would you not?
- Could you explain what the difference is between Delegate and KVO?
- What design patterns are commonly used in iOS apps?
- What design patterns besides common Cocoa patterns do you know of?
- Could you explain and show examples of SOLID principles?
- What options do you have for implementing storage and persistence on iOS?
- What options do you have for implementing networking and HTTP on iOS?
- How and when would you need to serialize and map data on iOS?
- What are the options for laying out UI on iOS?
- How would you optimize scrolling performance of dynamically sized table or collection views?
- How would you execute asynchronous tasks on iOS?
- How do you manage dependencies?
- How do you debug and profile things on iOS?
- Do you have TDD experience? How do you unit and UI test on iOS?
- Do you code review and/or pair program?
In the sections below we’ll go over each question, the reasoning behind it, the expected answer, and the answers that could raise a red flag for your interviewer.
1. What was the latest version of iOS you worked with? What do you like about it and why?
This question is typically asked to check how in touch are you with latest iOS tech and developments in Swift and the iOS platform.
The expectation is that you worked with at least the latest stable iOS version (iOS 10). But you get extra points if you’ve played with, or even updated your apps to, the current iOS beta (iOS 11). Talk about exciting new features iOS 11 has and why you like them. It is always good to have developers on your team who are passionate about the latest iOS technologies. Typically people who are curious enough to play with the new stuff come up with interesting new feature ideas or think of creative solutions.
It is usually a bad sign if a candidate hasn’t worked much with or isn’t interested in the current stable version of iOS. This means that most likely this person is not up to date on the latest technologies, solutions, and features iOS provides, which most likely means this person would either miss out on an opportunity to utilize the iOS system or, even worse, is not aware of some new pitfalls the latest system has.
2. What is an iOS application and where does your code fit into it?
This is a big picture question that could be asked in one form or another to gauge your understanding of what an iOS application is and where the code you write fits in it and in the iOS system overall.
We might think the apps we build are something special because they cover a unique use case. But your typical iOS application is just a giant, glorified run loop. It waits for user input and gets interrupted by external signals such as phone calls, push notifications, home button presses, and other app life cycle events. The only difference is that instead of being just a simple mail loop function that gets launched every time the user taps on your app icon, it has a higher level of abstraction,
AppDelegate, that we developers work with.
The rest of the code you write to implement the business logic of your app is placed somewhere in the “trigger points” delegated by that main loop to our app via
AppDelegate. That’s pretty much it. Simple. The code you write for your app, though, can be as simple as a method/function call or as complex as VIPER architecture. What you do with it is your choice.
Typically developers think of iOS apps as the code they write and the complex intricate details of the implementation, which are all true. But if you take a step back and look at the big picture, you can see what iOS apps really are - a run loop.
3. What features of Swift do you like or dislike? Why?
With the latest 3.2/4 Swift update it is proving again and again that this language is the future of iOS development. These days the expectation, especially from seasoned developers, is that you are well versed in Swift and the features it offers.
You could talk about strong typing and functional features of the language and why you like or dislike them. There’s no right or wrong answer here per se, but the expectation is that you are familiar with the language and the features it provides (generics, protocols, optionals, etc.). Also you should be able to explain and argue if you like or dislike something about the language (I’m not a fan of optional chaining because it breaks the Law of Demeter, for example).
Swift is becoming the major stable language for the iOS platform, so ignoring it these days doesn’t make sense.
4. How is memory management handled in iOS?
Memory management is very important in any application, especially in iOS apps that have memory and other hardware and system constraints. Hence, this is one of the questions that is asked in one form or another. It refers to ARC, MRC, reference types, and value types.
Swift uses Automatic Reference Counting (ARC). This is conceptually the same thing in Swift as it is in Objective-C. ARC keeps track of strong references to instances of classes and increases or decreases their reference count accordingly when you assign or unassign instances of classes (reference types) to constants, properties, and variables. It deallocates memory used by objects whose reference count dropped to zero. ARC does not increase or decrease the reference count of value types because, when assigned, these are copied. By default, if you don’t specify otherwise, all the references will be strong references.
This is a must know for every iOS developer! Memory leaks and app crashes are all too common due to poorly managed memory in iOS apps.
5. What do you know about singletons? Where would you use one and where would you not?
Singleton is a common design pattern used in many OOP languages, and Cocoa considers it one of the “Cocoa Core Competencies.” This question comes up from time to time on interviews to either gauge your experience with singletons or to find out if you have a background in something other than just iOS.
Singleton is a class that returns only one and the same instance no matter how many times you request it.
Singletons are sometimes considered to be an anti-pattern. There are multiple disadvantages to using singletons. The two main ones are global state/statefulness and object life cycle and dependency injection. When you have only one instance of something, it is very tempting to reference and use it everywhere directly instead of injecting it into your objects. That leads to unnecessary coupling of concrete implementation in your code instead of interface abstraction.
Another malicious side effect of “convenient” singletons is global state. Quite often singletons enable global state sharing and play the role of a “public bag” that every object uses to store some state. That leads to unpredictable results and bugs and crashes when this uncontrolled state gets overridden or removed by someone.
Even though in some languages/platforms singletons are considered to be good, they are in fact an anti-pattern that should be avoided at all costs.
6. Could you explain what the difference is between Delegate and KVO?
With this question your interviewer is assessing your knowledge of different types of messaging patterns used in iOS.
Both are ways to have relationships between objects. Delegation is a one-to-one relationship where one object implements a delegate protocol and another uses it and sends messages to it, assuming that those methods are implemented since the receiver promised to comply to the protocol. KVO is a many-to-many relationship where one object could broadcast a message and one or multiple other objects can listen to it and react. KVO does not rely on protocols. KVO is the first step and the fundamental block of reactive programming (RxSwift, ReactiveCocoa, etc.)
A seasoned developer should know what the difference is between the two and where one should be used over another.
7. What design patterns are commonly used in iOS apps?
This question is a common one on interviews for positions of all levels, maybe with the exception of junior positions. Essentially the idea is that in working with the iOS platform, you as a developer should be familiar with commonly used techniques, architecture, and design patterns used on iOS.
Typical commonly used patterns when building iOS applications are those that Apple advocates for in their Cocoa, Cocoa Touch, Objective-C, and Swift documentation. These are the patterns that every iOS developer learns. They include MVC, Singleton, Delegate, and Observer.
When an interviewer asks this question (in one form or another) the interviewer is looking for something besides MVC. Because MVC is the go-to design pattern, the expectation is that every iOS developer knows what it is. What they want to hear from you, though, is what else is commonly used and available out of the box.
8. What are the design patterns besides common Cocoa patterns that you know of?
This is an advanced question that an interviewer will ask when you interview for a senior or architect position. The expectation is that you know more practical design patterns used in iOS apps besides the basic ones covered in the previous question. Be ready to recall a bunch of Gang of Four patterns and other similar patterns.
Unfortunately design patterns are a huge topic on their own (they are also better covered in my book), so here I'll give only an overview of some of them that I see occur commonly in iOS codebases.
Besides commonly used MVC, Singleton, Delegate, and Observer patterns, there are many others that are perfectly applicable in iOS applications: Factory Method, Adapter, Decorator, Command, Template, and many other.
Factory Method is used to replace class constructors, to abstract and hide objects initialization so that the type can be determined at runtime, and to hide and contain
switch/if statements that determine the type of object to be instantiated.
Adapter is a design pattern that helps you, as the name suggests, adapt the interface of one object to the interface of another. This pattern is often used when you try to adapt third-party code that you can’t change to your code, or when you need to use something that has an inconvenient or incompatible API.
Decorator is a wrapper around another class that enhances its capabilities. It wraps around something that you want to decorate, implements its interface, and delegates messages sent to it to the underlying object or enhances them or provides its own implementation.
Command is a design pattern where you’d implement an object that represents an operation that you would like to execute. That operation can have its own state and logic to perform the task it does. The main advantages of this design pattern are that you can hide internal implementation of the operation from the users, you can add undo/redo capabilities to it, and you can execute operations at a later point in time (or not at all) instead of right away where the operation was created.
Template is a design pattern where the main concept is to have a base class that outlines the algorithm of what needs to be done. The base class has several abstract methods that are required to be implemented by its concrete subclasses. These methods are called hook methods. Users of the Template Method classes only interact using the base class that implements the algorithm steps; concrete implementations of those steps are supplied by subclasses.
Sticking only to MVC, Singleton, Delegate, and Observer patterns is fine when you’re just starting with the iOS platform, but for advanced things you need to reach deeper into more abstract and high-level stuff like Gang of Four OOP Design Patterns. They are very useful and make your codebase more flexible and maintainable.
9. Could you explain and show examples of SOLID principles?
SOLID principles are relatively old but incredibly useful concepts to apply to any OOP codebase in any language. Watch a few of Uncle Bob’s talks on the topic to fully appreciate the history behind them.
On YouTube: Bob Martin SOLID Principles of Object Oriented and Agile Design.
Unfortunately SOLID principles are a huge topic on their own (they are also better covered in my book), so here I'll give only an overview of them.
SOLID stands for Single Responsibility Principle, Open/Closed Principle, Liskov Substitution Principle, Interface Segregation Principle, and Dependency Inversion Principle. These principles feed into and support each other and are one of the best general design approaches you could take for your code. Let’s go through each of them.
The Single Responsibility Principle (SRP) is the most important principle of the group. It states that every module should have only one responsibility and reason to change. SRP starts with small concrete and specific cases such as a class and/or an object having only one purpose and being used only for only one thing.
The Open/Closed Principle (OCP) states that your modules should be open for extension but closed for modification. It’s one of those things that sounds easy enough but is kind of hard to wrap your head around when you start to think about what it means. Effectively it means that when writing your code you should be able to extend the behavior of your objects through inheritance, polymorphism, and composition by implementing them using interfaces, abstractions, and dependency injection.
The Liskov Substitution Principle (LSP) states that objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program. What that means is that when you inherit from a class or an abstract class or implement an interface (protocol), your objects should be replaceable and injectable wherever that interface or class that you subclassed from was used. This principle is often referred to as design by contract or, as of late in the Swift community, referred to as protocol-oriented programming. The main message of this principle is that you should not violate the contract that your interfaces you subclass from promise to fulfill, and that by subclassing, those subclasses could be used anywhere that the superclass was previously used.
The Interface Segregation Principle (ISP) says many client-specific interfaces are better than one general-purpose interface. It also states that no client should be forced to depend on and implemented methods it does not use. What that means is that when you create interfaces (protocols) that your classes implement, you should strive for and depend on abstraction over specificity, but not until it becomes a waste where you have to implement a bunch of methods your new class doesn’t even use.
The Dependency Inversion Principle (DIP) states, “depend on abstractions, not concretions.” The best example that showcases this principle is the Dependency Injection (DI) technique. With the Dependency Injection technique, when you create an object, you supply and inject all of its dependencies upon its initialization or configuration rather than let the object create or fetch/find its dependencies for itself.
SOLID principles are the bedrock of good OOP design. Applying these principles will help you build better, more maintainable software. It is highly advised to be well versed in them if you are applying to a senior iOS position.
10. What options do you have for implementing storage and persistence on iOS?
Interviewers ask this question to grasp your understanding of what tools and ways you have available to store and persist data on iOS.
Generally there are the following ways to store data in order from simple to complex:
- In-memory arrays, dictionaries, sets, and other data structures
- File/Disk storage
- Core Data, Realm
In-memory arrays, dictionaries, sets, and other data structures are perfectly fine for storing data intermediately or if it doesn't have to be persisted.
NSUserDefaults/Keychain are simple key-value stores. One is insecure and the other is secure, respectively.
File/Disk storage is actually a way of writing pieces of data (serialized or not) to/from a disk using NSFileManager.
Core Data and Realm are frameworks that simplify work with databases.
SQLite is a relational database and is good when you need to implement complex querying mechanics and Core Data or Realm won't cut it.
You should be aware of different ways you could store data on iOS and their advantages or disadvantages. Don’t limit yourself to only one solution that you’re used to (like Core Data, for example). Know when one is preferable over the other.
11. What options do you have for implementing networking and HTTP on iOS?
Virtually every application these days is using some kind of networking to get data from APIs and other external resources. A lot of the apps are useless when they are not connected to the internet. Every iOS developer should know what's available to them to build the service/networking layer of their application.
In iOS there are several options to implement HTTP networking. You can go with good old NSURLSession, but unless you abstract it out well enough, it can be daunting to work with. Another option would be to use a wrapper library around it. The most popular solution on iOS is Alamofire/AFNetworking.
Senior developers should keep in mind that building the networking layer in iOS applications does not only mean dealing with HTTP requests. It also means implementing the whole set of tasks your code does related to that: HTTP networking, data serialization, and data mapping.
These days, AFNetworking and Alamofire are the de facto standard for doing HTTP networking on iOS, and every developer should know how to use them. At the same time, they are all based on Apple frameworks, and knowing the inner details of NSURLSession is also beneficial.
12. How and when would you need to serialize and map data on iOS?
Data serialization is a common task that you need to perform when building iOS applications. Interviewers ask this question to see if you recognize the situations where it is suitable and are aware of the tasks you need to perform working with data, whether it is networking or storage data.
There are two most common scenarios where you'd need to serialize and map data in iOS applications: receiving or sending data in the networking layer (such as JSON or XML or something else), and persisting or retrieving models in the storage layer (NSData, NSManagedObject, etc.).
Every time you receive JSON or XML or any other kind of response from a backend API, you most likely get it in a JSON or binary or other “inconvenient” format. The first thing you need to do to be able to work with the data you’ve received is to serialize it in something your app understands. At the most simplest and basic level that would be a dictionary or array of objects containing other dictionaries, arrays, and primitives from that response. NSJSONSerialization takes care of that (and soon Codable protocol). The next step is to map that data into domain models of your application. Those would be the model objects the rest of your application works with. You can either do it manually or use a library such as Mantle or SwiftyJSON. The flow of data and serialization/mapping is as follows:
binary data ->
your domain model objects.
Similarly in the storage layer, you will need to serialize and map your data to and from your custom domain model objects to the format your storage understands. The “mapping” chain for reading data looks like this:
raw data format ->
custom domain models, and for writing like this:
custom domain models ->
raw data format ->
db. You'd use the NSManagedObject or NSCoding protocol here to achieve that.
The main red flag here is not being aware that these data manipulations need to happen when working with the networking and storage layers of your iOS applications. Things do not happen "automagically" nor is working with raw NSDictionaries appropriate and maintainable.
13. What are the options for laying out UI on iOS?
Knowing your options for laying out things on the screen is crucial when you need to solve different UI challenges on iOS. This question helps gauge your knowledge about how you put and align views on the screen. When answering this question you should at least mention CGRect Frames and AutoLayout, but it would be great to mention other options such as ComponentKit and other Flexbox and React implementations on iOS.
Go-to options for laying out views on the screen are good old CGRect Frames and AutoLayout. Frames, along with auto-resizing masks, were used in the past before iOS 6 and are not a preferred option today. Frames are too error-prone and difficult to use because it’s hard to calculate precise coordinates and view sizes for various devices.
Since iOS 6 we have AutoLayout, which is the go-to solution these days and which Apple prefers. AutoLayout is a technology that helps you define relationships between views, called constraints, in a declarative way, letting the framework calculate precise frames and positions of UI elements instead.
There are other options for laying out views, such as ASDK (Texture), ComponentKit, and LayoutKit, that are more or less inspired by React. These alternatives are good in certain scenarios when, for example, you need to build highly dynamic and fast table views and collection views. AutoLayout is not always perfect for that and knowing there are other options is always good.
Not mentioning at least AutoLayout and the fact that Frames are notoriously hard to get right is definitely going to be a red flag for your interviewer. These days no sane person would do CGRect frame calculations unless it is absolutely necessary (for example, when you do some crazy drawings).
14. How would you optimize scrolling performance of dynamically sized table or collection views?
One of the important questions that is sometimes asked on interviews along with UITableView questions is a question about table view scrolling performance.
Scrolling performance is a big issue with UITableViews and quite often can be very hard to get right. The main difficulty is cell height calculation. When the user scrolls, every next cell needs to calculate its content and then height before it can be displayed. If you do manual Frame view layouts then it is more performant but the challenge is to get the height and size calculations just right. If you use AutoLayout then the challenge is to set all the constraints right. But even AutoLayout itself could take some time to compute cell heights, and your scrolling performance will suffer.
Potential solutions for scrolling performance issues could be
- calculate cell height yourself
- keep a prototype cell that you fill with content and use to calculate cell height
Alternatively, you could take a completely radical approach, which is to use different technology like ASDK (Texture). ASDK (Texture) is made specifically for list views with dynamic content size and is optimized to calculate cell heights in a background thread, which makes it super performant.
15. How would you execute asynchronous tasks on iOS?
Multithreading is a vital part of any client-side, user-facing application these days. This question could be asked in the context of networking or as a standalone question about GCD or async development.
These days on iOS your go-to solutions for async tasks are NSOperations and GCD blocks. Grand Central Dispatch is a technology that was made to work with multiple background queues that in turn figure out which background thread handles the work. The main thing is that this is abstracted out from you so that you don't have to worry about it. NSOperation is an OOP abstraction on top of GCD that allows you to do more sophisticated async operations, but everything you could achieve with NSOperations you could do with GCD. Many Cocoa frameworks use GCD and/or NSOperations under the hood (NSURLSession for example).
There are alternative ways of handling async work using third-party libraries’ help. The most notable are Promises (PromiseKit), RxSwift, and ReactiveCocoa. RxSwift and ReactiveCocoa are especially good at modeling the asynchronous nature of time and work that needs to be done in the background and coordinated among threads.
The basics that every iOS developer should know in regards of async work are GCD and NSOperations. RxSwift and Promises are advanced concepts but senior developers should be aware of them as well.
16. How do you manage dependencies?
Dependencies management is an important task on every iOS project. This question is asked to gauge your understanding of the problem and how it can be solved.
A few years back we didn't have any dependency managers on iOS and had to copy-paste and drag and drop third-party code into our projects or to use git submodules. All of those approaches quickly proved to be unmanageable as our codebase and dependencies grew.
These days we have other dependency managers to choose from: CocoaPods, Carthage, and Swift Package Manager (SPM). So far the most dominant and robust one is CocoaPods. It was built in the spirit of the Ruby Bundler gem and is a Ruby gem itself. The way it works is you install the gem, create Podfile in the root directory of your project, declare the pods (libraries) you want to use, and run
pod install. That's it.
Every iOS developer should understand why copy-pasting third-party libraries into your codebase would lead to a maintenance nightmare when several libraries could depend on two different versions of another library, causing mismatches and compile and runtime issues, and so on.
17. How do you debug and profile things on iOS?
No one writes perfect code and occasionally developers need to debug their code and profile apps for things like performance and memory leaks.
There's always the good old
You can do more advanced debugging and profiling using Instruments. Instruments is a profiling tool that helps you profile your app and find memory leaks and performance issues at runtime.
18. Do you have TDD experience? How do you unit and UI test on iOS?
Even though, historically, the iOS community wasn't big on TDD, it is now becoming more popular thanks to improvements in tooling and influence from other communities, such as Ruby, that embraced TDD a long time ago.
TDD is a technique and a discipline where you write failing tests first before you write production code that makes them pass. The tests drive implementation and design of your production code, helping you write only the code necessary to pass the tests' implementation, no more, no less. The discipline could be daunting at first and you don't see payoff of that approach immediately, but if you stick to it, it helps you move faster in the long run. It is especially effective at helping you with refactoring and code changes because at any given time you have the safety net of your tests to tell you if something broke or if everything is still working fine as you change things.
Recently Apple made improvements to XCTest frameworks to make testing easier for us. They also made a lot of improvements with UI testing in Xcode, so now we have a nice programmatic interface to interact with our apps and query things we see on the screen. Alternatively you could go with frameworks like KIF.
In regards to unit testing, there are several options as well, but the two most popular ones are XCTest and Quick and Nimble.
XCTest is an xUnit like testing framework built by Apple. This is what they recommend to use, and it has the best integration with Xcode.
Quick is an RSpec-like BDD framework that helps you describe your specs/tests in terms of behavior rather than "tests." Fans of RSpec like it a lot.
Nimble is a matcher library that can be used with XCTest or Quick to assert expectations in your tests/specs.
More and more teams and companies embrace TDD, and it has become a vital part of the iOS development process. If you don't want to be left behind, get on board with it and learn how to test-drive your code.
19. Do you code review and/or pair program?
Even though there are a lot of applications out there that were built by solo developers, the complexity of what apps do keeps increasing, demanding that a team of developers work on it. Working in a team poses different challenges in terms of code maintenance, collaboration, and knowledge sharing.
Pair programming is a practice where two developers work on the same task together on the same machine (hopefully not sharing the same screen and keyboard and having two sets of their own). The goal is to facilitate collaboration, discussion, code review, and QA right where the code gets produced. This process makes knowledge transfer and architectural discussions a common day-to-day thing, preventing people from siloing and becoming "an expert" in a certain part of the code (what happens when that person leaves or gets sick?). It also improves code quality because two sets of eyes are looking at the code as it's written. This process happens for two developers at the same time and is sometimes called synchronous.
Pair programming is not for everyone and could be an exhausting process if people's personalities do not match. But nevertheless it is one of the most efficient collaboration techniques in software development.
Code review is a similar process of collaboration and knowledge transfer, but unlike pair programming, it doesn't happen at the same time, and therefore it is asynchronous. With code review, after a developer writes a piece of code or a feature, someone else on the team has a look at it. The reviewer checks if the code makes sense and suggests changes and refactorings to be done to improve it. That opens up an online or offline discussion about the code, which is great. That transfers knowledge about that piece of code to other teammates and helps catch bugs and design smells early on.
Code reviews are a less-involved type of collaboration that achieves much of the same results as pair programming does. It also is an exercise in empathy where you're giving feedback to others on their work.
The questions covered in this post touch upon a broad spectrum of topics iOS developers should know. This is by no means a comprehensive list. These questions are based on research I've done for the book, The iOS Interview Guide, which I published. The book approaches interview prep as a holistic overview of iOS topics and concerns every iOS application has. It breaks down questions into the following groups: UI-related questions (UIView, AutoLayout, etc.), storage questions (persistence, user defaults, core data, etc.), networking (HTTP, NSURLSession, Alamofire, etc.), and design patterns and architecture questions (MVC, MVVM, SOLID, etc.).
You can find out more here: http://iosinterviewguide.com/