Sold To
Sold To
Sold To
aidar.gf@gmail.com
2
working together. This humility translates into what makes him a great teacher
and mentor. Alex doesn’t speak down to you. He speaks plainly and if you
don’t understand something he’ll clarify it for you. Whenever I needed guid-
ance, I knew Alex would graciously share his time with me until I had a full
understanding.
Foreword Alex has a very pragmatic problem solving style. He understands that, at the
end day, us software engineers are there to help a business make more money.
If he talks architecture or algorithms he stays grounded in reality. He knows
that your employer doesn’t care what hip framework you used or what esoteric
By Andrew Rohn, iOS Software Engineer at Reddit and Co-Host of Inside algorithm you vainly implemented. He realizes that good code is an asset to the
iOS Dev Podcast company and that bad code can cripple a company from being able to keep up
with competitors. I attribute this to his time as a successful consultant where
Thanks to ‘The iOS Interview Guide’, I skillfully interviewed with Facebook,
clients needed a software system that would drive their business. Alex knows
Uber, Reddit, Pandora, and many other great companies and I now work at
that employers want to see that you can consistently ship quality code in a
Reddit as an iOS Software Engineer.
timely manner.
In one interview, I gave an answer to a system design question that was so good
Lastly, Alex has a boundless curiosity that ceaselessly propels his skills for-
that the interviewer asked me “Have you solved this problem before?”. To
ward. He is constantly reading books, watching talks, and trying new things.
which I responded truthfully, “No.” Later, he mentioned that the sophistication
After working with him, these habits have rubbed off on me. We had an in-
and quality of my answer greatly exceeded that of someone with only one year
formal book club every morning where he shared with me his new insights or
of experience.
learnings and encouraged me to share as well. This curiosity drove Alex to
My recent successful interview process is direct evidence of the authority and being knowledgeable not just in the iOS world but in the entire full stack. He
quality of this book. If you need more convincing about the quality of this book has created systems that required both a backend application and client iOS ap-
or if you’d like to learn more about the author – continue reading this foreword. plication. Because of this, he has a rare and invaluable end-to-end system per-
Otherwise, I recommend you get straight to reading this book so that you can spective. This unquenchable curiosity is what gives me confidence in Alex’s
crush your next interview! word. He is an authority because he is always reaching for the next level of
I think Alex is the perfect author for this book for three reasons: humility, understanding.
pragmatism, and curiosity.
I’m a junior iOS Software Engineer with just one year of professional expe-
rience. My first year working professionally was done under the mentorship
of Alex. I worked closely with Alex at Wanelo where we pair programmed
together every other day. I think Alex might quibble at being called my “men-
tor”. He might prefer something that defines our work relationship as equals
v vi
level of your career!”
– Paul DeFilippi, iOS Developer
“As a junior developer, I just want to say that the information you’re sharing is
top notch and extremely eye-opening to the naive approaches that I have taken.
Thank you so much for doing this.”
Testimonials – Jovanny Espinal, iOS Software Engineer at Blue Apron
“I am glad to inform you that your book on Swift Interview question helped me
a lot , I have two current jobs under process for next rounds. All of the question
Will’s video testimonial on YouTube I have answered the same way as you wrote in Expected Answer. It is really
– Will Lundy, iOS Developer at Wells Fargo worth buying it .”
Yusuke’s video testimonial on YouTube – Ramkrishna Baddi, iOS Developer
– Yusuke Kawanabe, Lead iOS Engineer at Nima. “An excellent guide to help self-starter iOS programmers land their dream
jobs. This book can be your ultimate guide for your iOS development study
Alex Bush’s book, “The iOS Interview Guide” is a very helpful resource for a as well as getting your first job as an iOS developer.”
variety of reasons. It helps the experienced developer prepare for their next
career move by identifying concepts, and areas that technology companies will – Jon Lu, Freelance iOS Developer
ask about during the application, and interview process. The book is an ex-
cellent resource because it’s not simply a checklist of topics, and concepts, to
study, but also discusses these concepts as well, and identifies potential pitfalls
that the unsuspecting applicant may fall into during the interview process. This
book is also a valuable resource for the junior developer who is trying to get
an understanding as to what skills are expected from someone who is senior.
This book helps chart a course for the junior developer in better improving
their skills, and identifying those key areas which are important, thus allowing
the junior developer to plan out their career development more efficiently. This
book is indeed a valuable resource for developers in all stages of their careers.
Thanks Alex for doing such a wonderful job!
– Fayyazuddin Syed, Senior iOS Developer
“Alex has hit a home-run with the iOS interview guide. It has been my go to
reference while looking for a job in this field. I can’t thank him enough for
sharing his insight into what it takes to be prepared for an interview at any
vii viii
1.2.7 Step Seven: Beyond MVC: Design Patterns, Architec- 3.2.3 Onsite Interview . . . . . . . . . . . . . . . . . . . . 29
ture, FRP, and Dependencies Management . . . . . . . 4
3.2.4 Salary Negotiation Interview . . . . . . . . . . . . . . 30
1.3 Bonus Content . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.3 Importance of Soft Skills . . . . . . . . . . . . . . . . . . . . 30
3.4 Keep Track of Progress . . . . . . . . . . . . . . . . . . . . . 31
2 Step One: Figure Out what the Big Picture Is 7
3.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.1 What is an iOS application and where does your code fit into it? 8
2.2 Patterns and Layers . . . . . . . . . . . . . . . . . . . . . . . 12
4 Step Three: Learn the fundamentals 33
2.2.1 Storage Layer . . . . . . . . . . . . . . . . . . . . . . 12
4.1 What is let and var in Swift? . . . . . . . . . . . . . . . . . . 34
2.2.2 Service Layer . . . . . . . . . . . . . . . . . . . . . . 13
4.2 What is Optional in Swift and nil in Swift and Objective-C? . 35
2.2.3 UI Layer . . . . . . . . . . . . . . . . . . . . . . . . 14
4.3 What is the difference between struct and class in Swift?
2.2.4 Business Logic Layer . . . . . . . . . . . . . . . . . . 14 When would you use one or the other? . . . . . . . . . . . . . 37
2.3 Zooming Out . . . . . . . . . . . . . . . . . . . . . . . . . . 16 4.4 How is memory management handled in iOS? . . . . . . . . . 38
2.4 Zooming In . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 4.5 What are properties and instance variables in Objective-C and
Swift? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.6 What is a protocol (both Obj-C and Swift)? When and how is
it used? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3 Step Two: The Interview Game. 19
4.7 What is a category/extension? When is it used? . . . . . . . . 42
3.1 Before The Interview . . . . . . . . . . . . . . . . . . . . . . 19
4.8 What are closures/blocks and how are they used? . . . . . . . 43
3.1.1 Job Search . . . . . . . . . . . . . . . . . . . . . . . 20
4.9 What is MVC? . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.1.2 Figure out what team/company size you want to work
with . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 4.10 What are Singletons? What are they used for? . . . . . . . . . 45
3.1.3 Marketing . . . . . . . . . . . . . . . . . . . . . . . . 23 4.11 What is Delegate pattern in iOS? . . . . . . . . . . . . . . . . 46
3.1.4 Preparation (Know Your Shit!) . . . . . . . . . . . . . 27 4.12 What is KVO (Key-Value Observation)? . . . . . . . . . . . . 47
3.2 At The Interview . . . . . . . . . . . . . . . . . . . . . . . . 27 4.13 What does iOS application lifecycle consist of? . . . . . . . . 47
3.2.1 Phone Intro . . . . . . . . . . . . . . . . . . . . . . . 28 4.14 What is View Controller? What is its lifecycle? . . . . . . . . 51
3.2.2 Phone and/or Skype/Hangout/Voip Interview . . . . . 28 4.15 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
xii xiii
6.4 What is NSUserDefaults? . . . . . . . . . . . . . . . . . . . . 81 7.13 How do you optimize table views performance for smooth, fast
scrolling? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.5 What is Keychain and when do you need it? . . . . . . . . . . 82
7.14 How do you work with UICollectionView? . . . . . . . . . . 101
6.6 How do you save data to a disk on iOS? . . . . . . . . . . . . 82
7.15 How do you work with UIScrollView? . . . . . . . . . . . . . 102
6.7 What database options are there for iOS applications? . . . . . 83
7.16 What is UIStackView? When would you use it and why? . . . 103
6.8 How is data mapping important when you store data? . . . . . 85
7.17 What alternative ways of working with UI do you know? . . . 103
6.9 How would you approach major database/storage migration in
your application? . . . . . . . . . . . . . . . . . . . . . . . . 87 7.18 How do you make a pixel-perfect UI according to a designer’s
specs? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
6.10 Conclusion: . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
7.19 How do you unit and integration test UI? . . . . . . . . . . . . 104
7 Step Six: Go crazy responsive with UI layouts 89 7.20 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
7.1 What are the challenges in working with UI on iOS? . . . . . 91
8 Step Seven: Beyond MVC. Design Pattens, Architecture, FRP, and
7.2 What do you use to lay out your views correctly on iOS? . . . 92
Dependencies Management. 107
7.3 What are CGRect Frames? When and where would you use
8.1 What design patterns are commonly used in iOS apps? . . . . 108
them? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
8.1.1 MVC . . . . . . . . . . . . . . . . . . . . . . . . . . 109
7.4 What is AutoLayout? When and where would you use it? . . . 94
8.1.2 Singleton . . . . . . . . . . . . . . . . . . . . . . . . 109
7.5 What are compression resistance and content hugging priorities
for? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 8.1.3 Delegate . . . . . . . . . . . . . . . . . . . . . . . . 109
7.6 How does AutoLayout work with multi-threading? . . . . . . 96 8.1.4 Observer . . . . . . . . . . . . . . . . . . . . . . . . 109
7.7 What are the advantages and disadvantages of creating Auto- 8.2 What is MVC? . . . . . . . . . . . . . . . . . . . . . . . . . 110
Layouts in code versus using storyboards? . . . . . . . . . . . 96
8.3 What is MVVM? . . . . . . . . . . . . . . . . . . . . . . . . 112
7.8 How do you work with storyboards in a large team? . . . . . . 97
8.4 What are the common layers of responsibility that an iOS ap-
7.9 How do you mix AutoLayout with Frames? . . . . . . . . . . 98 plication has? . . . . . . . . . . . . . . . . . . . . . . . . . . 116
7.10 What options do you have with animation on iOS? . . . . . . 98 8.4.1 UI Layer . . . . . . . . . . . . . . . . . . . . . . . . 116
7.11 How do you do animation with Frames and AutoLayout? . . . 99 8.4.2 Service Layer: . . . . . . . . . . . . . . . . . . . . . 117
7.12 How do you work with UITableView? . . . . . . . . . . . . . 100 8.4.3 Storage Layer: . . . . . . . . . . . . . . . . . . . . . 117
xv xvi
8.4.4 Business Logic Layer: . . . . . . . . . . . . . . . . . 118 9.4 NSUserDefaults and Keychain . . . . . . . . . . . . . . . . . 151
8.5 What are SOLID principles? Can you give an example of each 9.4.1 NSUserDefaults . . . . . . . . . . . . . . . . . . . . 152
in iOS/Swift? . . . . . . . . . . . . . . . . . . . . . . . . . . 119 9.4.2 Keychain . . . . . . . . . . . . . . . . . . . . . . . . 155
8.5.1 Single Responsibility Principle . . . . . . . . . . . . . 119 9.5 File/Disk Storage . . . . . . . . . . . . . . . . . . . . . . . . 156
8.5.2 Open/Closed Principle . . . . . . . . . . . . . . . . . 120 9.6 Core Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
8.5.3 Liskov Substitution Principle . . . . . . . . . . . . . . 121 9.6.1 Going the NSManagedObject Subclass Route . . . . . 161
8.5.4 Interface Segregation Principle . . . . . . . . . . . . . 121 9.6.2 Going the Data Mapping/Serialization Route . . . . . 161
8.5.5 Dependency Inversion Principle . . . . . . . . . . . . 126 9.7 Storage Layer Plays Dual Role: Persistence and Data Mapping
8.6 How do you manage dependencies in iOS applications? . . . . 129 and Serialization . . . . . . . . . . . . . . . . . . . . . . . . 166
9.8 Switching Storage . . . . . . . . . . . . . . . . . . . . . . . . 167
8.7 What is Functional Programming and Functional Reactive Pro-
gramming? . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 9.9 FRP in the Storage Layer. . . . . . . . . . . . . . . . . . . . . 167
8.8 What are the design patterns besides common Cocoa patterns 9.10 Be Practical in Your Storage Layer Implementation and Decisions168
that you know of? . . . . . . . . . . . . . . . . . . . . . . . . 132 9.11 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
8.8.1 Factory Method . . . . . . . . . . . . . . . . . . . . . 133
8.8.2 Adapter . . . . . . . . . . . . . . . . . . . . . . . . . 135 10 Outro 169
xvii xviii
• fixed storyboards mention in What are the advantages and disadvantages
of creating AutoLayouts in code versus using storyboards?
question in UI chapter.
• fixed minor typos
[1.0.4] - 2017-08-16
All notable changes to this project will be documented in this file.
Added:
The format is based on Keep a Changelog and this project adheres (somewhat)
to Semantic Versioning. • clarified how optionals work with lets
• clarified usage of scope defining lets
[1.0.6] (current) - 2018-9-10
Changed: Changed:
• all the code samples shipped with the book (see ios_interview_guide_v_1_0_6_code_samples • Fixed missing apostrophes in PDF version of the book
zip file) were rewritten with Swift 4 and made more idiomatically “Swifty”.
• this changelog moved to after the table of contents [1.0.2] - 2017-06-01
Removed: Changed:
Changed: Changed:
• fixed and clarified struct inheritance in Fundamentals chapter. • Fixed minor typos
xix xx
[1.0.0] - 2017-05-28 • Chapter 7 Step Six. Go crazy responsive with UI layouts (edited for typos
and structural improvements).
Added:
• Chapter 8 Step Seven: Beyond MVC. Design Pattens, Architecture, FRP,
• Outro and Acknowledgments and Dependencies Management. (edited for typos and structural im-
provements).
[0.8.3] - 2017-05-24 • Chapter 9 Bonus Chapter: Storage Evolution (AKA You Don’t Always
Need Core Data!). (edited for typos and structural improvements).
Added:
Changed:
[0.8.2] - 2017-05-23
• Chapter 2 Step One. Figure out what the big picture is. was restructured.
• Fixed and improved layout in all the chapters
Added:
[0.8.1] - 2017-05-15
• Chapter 1 Intro (edited for typos and structural improvements). • Added cross link references to chapters and questions/answers within
chapters for easy navigation
• Chapter 2 Step One: Figure Out what the Big Picture Is (edited for typos
and structural improvements).
Removed:
• Chapter 5 Step Four: Get Productive with Networking (edited for typos
and structural improvements).
• all the TODOs, notes, and unfinished content was removed from chapters
• Chapter 6 Step Five: Learn How to Store Data (edited for typos and
structural improvements). • overflowing chapter title at the top of each page was removed
xxi xxii
[0.7.1] - 2017-04-10 [0.4.0] - 2016-11-14
Changed: Added:
[0.7.0] - 2017-03-27
Added:
[0.6.0] - 2017-01-21
Added:
• This CHANGELOG
[0.5.0] - 2017-01-02
Added:
xxiii xxiv
1.1 Who am I?
My name is Alex. I’m a fellow developer like you. I’ve been working with iOS
for over six years, built over twenty apps, code reviewed thousands of lines
of code, mentored several developers, and interviewed a lot of developers. I
Chapter 1 know all the struggles you go through with iOS development and I know what
pitfalls there are. I founded Smart Cloud. I blog at http://www.sm-cloud.com/
and co-host Inside iOS Dev Podcast. And you can find me on LinkedIn here.
Intro
Ok, here we are. As developers we love our craft, and even more, we love to
be paid for the work we do. That is why we get jobs. And to get a better job
we need to go on those notorious interviews. . .
Do you hate them as much as I do? It takes so much time to prepare for them,
and you still can’t guess what crazy thing they’ll ask you on the interview,
making you sweat and jitter.
If so read on. This is a no BS, down to business, pragmatic guide on how to get
ready for your iOS interview. Whether you’re applying for a senior position or
just starting out as a junior, this guide will help you get over your anxiety and
actually give you concrete steps and guidance on what you need to know as a
modern iOS developer. It will give you an overview of what there is to learn on
the iOS platform and systematize that stuff so that there’s clear structure and
guidance on what you need to learn next. 1.2 Structure of this book
The best way to not be nervous and to nail your interviews after all is to actually
know more and better than your interviewer. If you want to know “advanced This book is broken down into a series of seven steps that you can follow to get
stuff,” then this is the guide for you! a good grasp on what there’s to learn about the iOS platform and what kinds
of questions you could be asked on technical iOS interviews. Questions are
grouped into logical layers of responsibility which we will talk about more
in Chapter 2 Step One: Figure Out What the Big Picture Is, and we will talk
in more details about the architectural aspects of it in Chapter 8 Step Seven:
1 2
Beyond MVC: Design Pattens, Architecture, FRP, and Dependencies Manage- 1.2.5 Step Five: Learn How to Store Data
ment.
Chapter 6 covers everything storage and persistence. There are multiple ways
you could store data on iOS and in some scenarios certain solutions are better
than others. You’ll find answers to questions ranging from NSUserDefaults
1.2.1 Step One: Figure Out What the Big Picture Is to Core Data in this chapter.
3 4
Alright, without further ado, let’s get into it.
5 6
2.1 What is an iOS application and where does
your code fit into it?
If you think about it long enough, your typical iOS application is just a giant
Chapter 2 glorified run loop. It waits for user input and gets interrupted by external signals
such as phone calls, push notifications, home button press, and other app life
cycle events.
Following is Apple’s diagram of the iOS app life cycle:
Step One: Figure Out what
the Big Picture Is
A big picture overview makes it easier to orient yourself. So first things first
- find out what the iOS world is all about overall and what the high-level
overview of what you could possibly be asked about on iOS interviews is. You
can figure out the details later when necessary.
If you build enough apps you’ll start noticing patterns. You’ll see that there are
things you do over and over again in one form or another that are essentially the
same. When that happens, you realize how all apps are similar to each other.
Sure they might differ in looks and what they do for the user, but overall, the
way you build them is the same. Therefore when developers are interviewed
for any iOS position, they will be asked a similar set of questions revolving
around broad iOS topics. The main idea is that interviewers need to figure out
what you know about building iOS apps.
In this chapter, we’ll look at what iOS apps are, where they fit in the iOS
system, the big picture design patterns that emerge out of building iOS apps,
and how you can group and structure interview questions around those topics
to systematize your own learning.
It is indeed that simple and straightforward. The app is launched, and then it
7 8
sits and waits for user input, whether it’s a touch or a home button click to put
import UIKit
the app in the background, or something else.
//@UIApplicationMain
UIApplication is just an object built around the main() loop to augment it class AppDelegate: UIResponder, UIApplicationDelegate {
and give us more usability that calls convenient callbacks to your var window: UIWindow?
UIAppDelegate subclass. Those “convenient” callback methods would be:
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
• application:willFinishLaunchingWithOptions: [NSObject: AnyObject]?) -> Bool
{
• application:didFinishLaunchingWithOptions: let storyboard = UIStoryboard(name: "Main", bundle: nil)
9 10
displayed to the user. Try to run this and you’ll see a black screen instead of any kind of UI but notice
that all the methods like applicationDidBecomeActive and
But if you’d remove all that UI code, your application is still going to be a per-
applicationWillResignActive still call when you click on the home but-
fectly valid iOS app and it’s even going to launch! Heck, even all the callback
ton and open your app again. The UI is just your app’s code; the system doesn’t
methods that the main() loop under the hood sends to us will be received as
care if you have any or not. It just keeps running its main() loop.
they would be with a normal application that has a UI:
To the iOS system, your app is yet another building block, yet another run/main
import UIKit loop that can be launched on user demand or when some other event in the
//@UIApplicationMain system like push notification or location change happens.
class AppDelegate: UIResponder, UIApplicationDelegate {
11 12
the role of the “ultimate source of truth” for the rest of your code. Exam- 2.2.3 UI Layer
ples of what goes into this layer could be the following: Core Data, Realm,
NSUserDefaults, KeyChain, Disk File storage, and
The UI layer is responsible for drawing things on the screen. This is all the
in-memory arrays and dictionaries/sets.
stuff that naturally goes into that bucket like UIView subclasses, Autolayout,
We’ll cover interview questions around storage in Chapter 6 Step Five: Learn Table Views, Buttons, Collection Views, and Bar Buttons. Two
How To Store Data other things that also belong to this layer that might not be obvious are View
Controllers and View Models. View Controllers are suppose to do
just that, control the view. View Models are complimentary objects that help
2.2.2 Service Layer with decluttering and decoupling views from other layers of responsibility. Re-
member the key to a happy and healthy iOS codebase is a skinny controller.
This layer is responsible for all things involving networking and external com-
We’ll cover interview questions around UI and layout in Chapter 7 Step Six:
munication. That could be, as needed by pretty much any app these days, an
Go Crazy Responsive with UI Layouts
HTTP client and a set of accompanying objects that do networking for the app
and connect with the backend JSON API. Or it could be a Bluetooth Low
Energy (BLE) client wrapper code that helps your app communicate and send
or receive data from external Bluetooth devices. Or it could be a socket connec-
tion code that allows your app to subscribe to server events and receive, let’s
say, comments from another chat participant, or some other piece of data. Or it 2.2.4 Business Logic Layer
could be a location service that connects with a device’s GPS delegates and gets
location change updates. You get the picture. The bottom line is that it’s the
In this layer are objects that are responsible for the actual application’s business
code that knows how to work with external interfaces, whether it’s HTTP or
logic, objects that use components of other layers to achieve results and do the
BLE or something else. Also quite often data serialization and mapping (let’s
work for the user. Coordinators that use HTTP service objects in conjunction
say from JSON to your custom objects) are included in this layer as well.
with storages to orchestrate receiving data from backend APIs and persisting
We’ll cover interview questions around networking and services in Chapter 5 it to Core Data would be one example.
Step Four: Get Productive with Networking
Another example of what goes into this layer could be a manager object that
takes care of token encryption and saving to keychain using keychain storage
and some kind of encryption service in it.
The main idea is that this layer helps us keep services, storages, and other layers
decoupled from each other and tell them (aka orchestrate and coordinate) what
to do to achieve results. This layer is what actually makes your application
useful.
This is how the layers structure looks overall:
13 14
2.3 Zooming Out
So what does all of this mean for you and your interview prep? Layers in iOS
codebases that we just discussed essentially group all the things that you should
know as an iOS developer. That effectively means that when you prepare for
interview questions each one of those questions could be placed in a respective
group according to the purpose of the thing the question is asking about.
This is how this book is structured - instead of randomly preparing for questions
that were put together in some arbitrary way, we instead will systematically
take a look at each layer and the things you need to know there.
2.4 Zooming In
Now, when you know overall what there is to learn on iOS, you could go
through each step and chapter one by one, reading questions and answers in
order. Or you could skim them and skip the questions you already know an-
swers to and are familiar with and instead focus on those areas where you’re
lacking.
Regardless of the way you approach it, systematizing your learning and know-
ing overall where you are in grasping iOS should give you a framework to work
in and give you more confidence on the interviews themselves.
2.5 Conclusion
You might be wondering why you’re seeing this particular layers breakdown.
In this chapter we looked over the big picture of what there is to learn on iOS.
It is inspired by the Single Responsibility Principle (SRP), one of the SOLID
We now have a plan of attack for prepping for questions about each layer of
principles (which stands for Single Responsibility, Open/Closed, Liskov Sub-
responsibility a typical iOS application has.
stitution, Interface Segregation and Dependency Inversion). We’ll discuss it in
more detail in Chapter 8 Step Seven: Beyond MVC: Design Patterns, Archi- In the next chapter we are going to look at what a typical interview process
tecture, FRP, and Dependencies Management consists of and how you can increase your chances to get noticed and get invited
15 16
to be interviewed.
17 18
3.1.1 Job Search
Everything starts with a job search. There are several ways you can do this
and they are not mutually exclusive. You can apply for jobs through various
job boards and company websites, talk to your friends, get referrals through
Chapter 3 word-of-mouth, and work with recruiters.
Now, let’s look at these job search methods in more detail:
19 20
positions off your shoulders. After all, they are on your side. Sure, they get codebases here, all the projects are apps started from scratch, so called “green
a nice payout when you land a job. It’s in their interests, though, to get you field” projects.
the best job they can because if you get a big salary, they can negotiate with
Large Company:
your new employer for a bigger cut. Give them a good resume to use and make
adjustments to it if they ask for them. Also, tell them what you are ideally Interviewing at a large company (50+ people in the engineering team) you will
looking for and your salary preference. Then sit back and relax and let them probably be asked generic computer science questions and sometimes inter-
source new gigs for you (if they are any good, of course). viewers won’t even go into iOS-specifics. Big organizations have typically
already figured out what their product is and are scaling product and market-
Always remember, too, that if the recruiter you are working with is not produc-
ing efforts. For you, this means that the interview is likely to revolve around
ing results, don’t be discouraged. Try a different one and keep searching for
hypothetical problem-solving and scalability. Large organizations care about
jobs on your own.
the performance impact of file downloads, network requests, and other compu-
tations made on the client side. Unlike small organizations, there most likely
will be time for doing optimizations. Timelines in bigger organizations are
3.1.2 Figure out what team/company size you want to work longer and typically they are looking for people to fill specialized roles. You’ll
with often find that large organizations like Facebook or LinkedIn are looking for
developers (and even entire teams) to focus on things like UI performance, net-
working download speeds or other deeper specializations in iOS software that
Team size matters. It should influence your expectations as a developer and
smaller companies can’t spend time on. Also expect to be working with legacy
will affect the way an interview is conducted. When you apply for a position in
codebases.
a company, you need to know how big the engineering team in that company
is and what their culture is like. Then you’ll know the kinds of questions to Mid-size Company:
expect on your interview. When applying to a mid-size company (10 - 50 people), you should expect a
Small Company: mix of what small companies need and big companies expect. Mid-size com-
panies are not big enough to spare resources on people who specialize in things
If they are a small startup/company (0-10 people in the engineering team) with
like performance but aren’t small anymore to move super fast and risk breaking
“hackish” culture then they’ll most likely ask you about prototyping things
things. They’ll expect you to be a well-rounded and balanced developer. As
and will expect you to “build shit quickly” disregarding quality and praising
with a small company, in most cases you will be expected to build and ship
the speed. They won’t care much about good architecture and scalability or
things end-to-end but you will also have to keep an eye on performance, scal-
performance at early startup stage they care more about “time to market” which
ability, and architecture for future maintainability. If you interview at a good
means quickly putting together something that works most of the time and
mid-size company, the questions are likely to encompass all of these areas as
shipping it. The expectation on you as a developer (especially if you’ll be the
well as cover broad iOS, architecture and CS knowledge.
sole iOS developer on the team) would be that you can deliver apps end to
end - from the very first line of code down to the release submission to the I personally find teams at mid-size companies to be the most challenging and
app store with all the necessary provisioning profiles etc. You need to be able interesting to work with because they demand more than simply building an
to figure things out quickly. Most likely you won’t be working with legacy MVP. They need someone whose talents go beyond shaving microseconds off
21 22
networking performance or scrolling in table views. sume don’t have much time, so make it easier for them and keep it short and
concise. They’ll appreciate that.
The main message here is that you should figure out what type of company and
team you’d like to join ahead of time and prepare for your interview accord- If you’re applying to a US company, your resume structure should probably be
ingly. Regardless of your choice, though, the advice in the following chapters as follows (sections going from top to bottom):
about interview questions on UI, Networking, Storage, and other technical iOS
topics will help you prepare for interviews at any company regardless of its 1. Your name and contact information, such as e-mail and phone number,
size. should go at the very top. Below these you should add links to your blog
and profiles on GitHub, Stack Overflow and anywhere else that show-
cases you as a great developer. Don’t overdo it by including more than a
3.1.3 Marketing few, though.
This is something that most developers neglect. I know the word “marketing” 2. Your work experience. Include the names of companies you’ve worked
can sound sleazy and unappealing. Yet, when you’re aiming at your dream job, at and your positions along with the dates of your employment. Also,
you need to stand out from the crowd if you want to get a foot in the door. add a very short (one or two sentence) description of what you did along
the lines of, “I was working on the main iOS app and successfully imple-
The way to do this is through marketing yourself with your resume, your blog, mented integration with internal JSON API”. You can also mention one
your GitHub profile, and other links and resources that showcase you as a great or two big technologies or architectural concepts you used at each job.
developer and an appealing candidate.
3. Your personal projects. This would include any relevant interesting stuff
you’ve done aside from paid work.
Resume
4. Your education. State the name of the college or university you went to
and what you majored in but nothing else. Employers won’t really care
There’s a notion that resumes are overrated and that some companies don’t
about your education unless they are Google, or Amazon, or a similar
even look at them. Ignore it. There are still plenty of HR personnel and other
size company.
recruitment gatekeepers that filter candidates out based on resumes so it makes
sense to have a good one. 5. Optionally, you can also have a section with any special expertise you
The main purpose of a resume is to briefly show that you have relevant experi- have that might be relevant. In my resume, for example, I have Func-
ence for the position you’re applying for. It won’t get you the job though, you tional Reactive Programming (FRP) and SOLID principles. This section
will still have to interview but it will increase your application response rate. is not essential and can be omitted if it makes your resume too long or
complicated.
HR departments and other people involved in hiring devs typically get hundreds
of resumes a day and have very limited time to spend on each one. Therefore,
Don’ts:
keep your resume under two pages and don’t overly complicate it with long,
smart-sounding words and corporate BS. Again, people who look at your re- Do NOT include the following things in your resume:
23 24
• photo of yourself Google it a lot. Find out what their team size is and what tech they work
with. Read any technical and product blogs they have. Most importantly of all,
• marital status research and, if possible, try out the product they make. You can’t imagine how
many developers are disregarded for jobs simply because they show no interest
• date of birth
in the products made by the company they’re applying to.
• career objective
Github
It’s unfortunately true that by excluding the first three of these from your re-
sume you can avoid sources of negative bias. If you represent a minority group, Your code speaks more loudly about you than anything else. GitHub is the
are of a certain age or have a some kinds of social status, it might influence a de facto standard for code version control nowadays. Not only should you
recruiter’s decision to consider you as a candidate. This is a complicated issue know how to use git well enough, you should also have an up-to-date GitHub
that could be the topic for another book so simply take my word for it and don’t profile.
include these things in your resume.
For some companies GitHub is the main tool used for filtering out applicants
As for stating your career objective, it’s just filler that no-one cares about in a for developer jobs. Having an active GiHub account shows that you’re a part
resume. If an employer is interested, they’ll ask you at the interview. of the software developer tribe and active in that community.
References: Your GitHub profile should have a very short description of what you can do
Don’t include references in your resume but have a few available. Offer to and showcase what you’ve worked on. Potential employers find it handy to
provide them upon request. go to someone’s GitHub profile and see their code before deciding whether to
invite them for an interview.
In that rare case where the code you wrote can’t be made public because of
Cover Letter
a non-disclosure agreement (NDA) or something similar, try to get a few code
samples together that you can share. We’ll discuss this more in the next section.
Cover letters are important. When you apply directly for jobs, the cover letter
will be the first impression you make. It can be a deal breaker or a deal maker.
If a company sees that you copy-and-pasted a form letter, they could take that Code Samples
to mean you don’t care about joining them specifically. If it looks like you’ve
taken the time to craft a cover letter for the company and the position you’re
Good code samples that are on a GitHub profile or have been included in your
applying for, you’ll greatly increase your chances of getting an interview. In
application often make potential employers more inclined to send out an in-
more general terms, keep your cover letter succinct, to the point and, for God’s
terview invitation. If you can’t share much in your GitHub profile due to an
sake, spell check!
NDA, ask your previous employers or clients if you can share only a portion of
Writing a good cover letter means doing your research. Unless you already the code you wrote. That could be a set of classes that constitute a feature that
know everything you need to know about the company you’re applying to, you built, networking code you’ve written, or something similar. Try to find
25 26
something that shows complete end-to-end coding for a feature you’ve built following steps: phone intro, phone/skype/hangout/voip interview, onsite
and reassure the owner of the intellectual property that you won’t reveal too interview, and optional negotiation interview.
much about the rest of the application.
Aside from the job search and marketing, the most important thing you need to 3.2.2 Phone and/or Skype/Hangout/Voip Interview
do before every interview is to prepare and learn as much iOS stuff as you can.
Tech skills and soft skills are actually what you’ll need day-to-day on your job
A second interview can take various forms. Typically it is a technical interview
so you’ve got to be ready. That is what the rest of this book is about. Specific
that could either be purely Computer Science-oriented (i.e., about algorithms,
questions that you should prepare for on UI, Storage, Networking and other
data structures, etc.), or iOS-oriented (iOS tech questions with short answers
things that you’ll need to know are broken down in subsequent chapters. Read
to gauge your overall knowledge). It might also have a mix of both. These in-
them.
terviews can be either over the phone, so you’d be expected to just talk, or they
could be conducted via Skype, Google Hangouts or another VoIP service. You
might be asked to use VoIP so you can share your screen and the interviewer
3.2 At The Interview can see what you’re typing while you solve a problem they’ve given you.
These interviews are typically not as crazy hard as you might think and they
When you’re interviewing with a company you’ll actually have multiple inter- usually take from 30 minutes to an hour. If they take longer than this that can
views at different stages of the process. Typically these break down into the be a good sign.
27 28
Again, get ready for the technical questions by reading the chapters of this to see is how you tackle problems and how well you know iOS stuff. Take a
book. deep breath, be calm, and talk your solutions through. Ask questions if you
need to clarify something.
It’s okay to ask the interviewer to repeat a question that you didn’t understand.
If they give you a problem to solve, talk through your solution before typing
it out. Usually, the interviewer just wants to understand how you think rather Pair Programming
than see you get the right answer of the bat.
I have one other important piece of advice if you are asked to interview via Pair programming is one of the best ways to gauge a candidate’s level of ex-
a VoIP service: ensure that you have a stable internet connection (preferably perience and general cultural fit. That’s because it’s the closest thing possible
through a cable because WiFi is unreliable) and a quiet spot to talk for an hour to what the interviewee will actually be doing on the job if hired. The same
because you don’t want the interview to get interrupted or cut off in the middle. advice applies here as with other types of interviews: be calm, don’t hesitate
to ask questions, and talk your solutions through because your interviewer will
want to know how and why you’ve decide to write a particular piece of code
3.2.3 Onsite Interview before you do it.
Onsite interviews are generally the hardest and longest. The interview style,
questions, organization, and other details will vary from one company to an- 3.2.4 Salary Negotiation Interview
other depending on their size and culture. In general, though, expect there to
be at least one whiteboarding session (with or without CS and iOS questions, A salary negotiation interview sometimes happens right after your on-site in-
architectural discussion and problem solving), one or more pair programming terview or might occur later over the phone or VoIP. Negotiating is usually the
sessions or a mix of each of these. Again, questions covered in the rest of this hardest thing for developers to do and many simply agree to whatever is of-
book will help you prepare. fered. There’s a lot of benefit to be gained from discussing salary, though. Lis-
Dress well to make a good impression, even if you’re going to a hip startup in ten to Ruby Rogues Podcast Episode #274 for an at-length discussion of why
Silicon Valley it’s important and what tactics will help you do it successfully. John Sonmez
also covers salary negotiation in his great book Soft Skills.
Even if you’ve asked questions in a previous interview about the company and
the team that you could be working with, prepare more. You will be given a If you work with a recruiter, they should take care of this part for you.
chance to ask them and they will show the extent of your interest in working
specifically for the company that is interviewing you.
3.3 Importance of Soft Skills
Whiteboarding
So called “soft skills” are a set of your skills such as people skills, communi-
Whiteboarding can be intimidating for people but don’t get discouraged. It’s cation skills, productivity skills, organizational skills, attitudes and emotional
not an exam and you’re not in school anymore. What interviewers really want intelligence (EQ). In other words, anything that is not directly related to, but
29 30
is just as important as, your “hard skills” or technical knowledge. Sometimes
teams will prefer someone who is a great communicator over a coding genius
who can’t get along with others. So, in your interviews be at your best and
smile to make a good impression on the people you’re interviewing with
Read that John Sonmez book for more on this topic.
3.5 Conclusion
In this chapter we went through the overall structure of the interview process.
It should be easier for you to handle now that you know what to expect. The
rest of this book covers the technical knowledge you will need to be calm and
confident enough in your interviews to crush them!
31 32
• What is a protocol (both Obj-C and Swift)? When and how it is used?
33 34
without breaking everything (i.e. throwing an exception). In Swift, though,
if let unwrappedOptional = someOptional {
you have to be very explicit about what you are declaring. // your code here
}
At the end of the day, let, var, nil, and Optionals (as you’ll see in the
next section) help define how you handle state in your apps. Swift forces you
to be more explicit about it. construct.
Optionals can be used with constants (lets) only if they were give a value
right away (whether it’s nil or an actual value). In general a constant has to
be defined at the time of its declaration and therefore it has a value and is not
4.2 What is Optional in Swift and nil in Swift and an Optional.
Objective-C? In Swift, unlike in Objective-C, sending messages to nil causes a runtime
exception. There is, though, a way of sending a message to an Optional in
This is another fundamental Swift question that you should be expecting in Swift and if the value is a nil, it will just ignore the message and return nil
iOS interviews. Different from Objective-C treatment of nils and introduc- instead of raising an exception. This is much like the old Objective-C behavior
tion of Optionals makes Swift development style in some cases dramatically and allows you to do method chaining calls. If one of the Optional values in
different from Objective-C. Be ready to talk at length about the big picture ar- the call sequence is nil, the whole chain will return nil.
chitectural implications of this and how it is going to affect how you write your Optionals make Swift lean more towards the functional side of programming
code. languages partially mimicking the Maybe concept of Haskel and similar lan-
Expected answer: In Objective-C nil used to be a very handy “value” for guages. Ultimately, just like let, var, and nil, Optional is a helpful con-
variables. It typically meant an absence of value or simply “nothing”. You struct that forces you to be more mindful of how you handle the state of your
could send a message to a nil and instead of your app blowing up with an applications.
exception it would simply ignore it and do nothing (or return nil). With the In general, you should use nil and consequently Optionals to represent an
introduction of let and var in Swift, however, it became apparent that not all absence of value as little as possible. Every time you declare an Optional, ask
constants and variables can be defined and set at the time of declaration. We yourself if you really, really need it.
needed to somehow declare that a variable has not been determined yet and that
it potentially could have a value or no value. That’s where Optional comes NOTE: Objective-C now has nonull and nullable directives to give it
into play. explicit variable type declaration, which is more Swift-like.
Optional is defined with ? appended at the end of the variable type you
declare. You can set a value to that variable right away or at a later time or not Red flag: Besides not knowing what Optionals are and how to work with them,
set one at all. When you use Optional variables you have to either explicitly the biggest red flag for an interviewer would be if you speak in favor of Op-
unwrap them, using ! at the end of the variable to get the value stored in it or tional Binding and explicit Optional Unwrapping. The former leads to poor
you could do a so-called Optional Binding to find out whether an Optional design and cognitive overhead of if/else statements and with the latter there is
contains a value. To do that you’d use a the potential danger of runtime exceptions.
35 36
4.3 What is the difference between struct and 4.4 How is memory management handled in iOS?
class in Swift? When would you use one or
the other? Memory management is very important in any application, especially in iOS
apps that have memory and other constraints. Hence, this is one of the standard
questions that is asked in one form or another. It refers to ARC, MRC, reference
types, and value types.
Expected answer: 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
Structs and classes in Swift are very similar and different at the same time. reference count accordingly when you assign or unassign instances of classes
This is another fundamental language question that could be asked to gauge (reference types) to constants, properties, and variables. It deallocates memory
your level of understanding of Swift and the features it offers. used by objects which reference count got down to zero. ARC does not increase
Expected answer: Both structs and classes in Swift can have properties, or decrease the reference count of value types because, when assigned, these
methods, subscripts or initializers, be extended, and conform to protocols. are copied. By default, if you don’t specify otherwise, all the references will
be strong references.
Classes are reference types. They increase their reference count when passed
to a function or assigned to a variable or constant. They also have some extra One of the gotchas of ARC that you need to be aware of is Strong Reference
stuff like inheritance from a superclass (structs can’t do that), type casting, and Cycles. For a class instance to be fully deallocated under ARC, it needs to be
deinitializers (former dealloc). free of all strong references to it. But there is a chance that you could structure
your code in such a way that two instances strongly reference each other and
Structs are so-called value types. That means that when a struct is as-
therefore never let each other’s reference count drop down to zero. There are
signed to a variable or a constant, or is passed to a function, its value is copied
two ways of resolving this in Swift: weak references and unowned references.
instead of increasing its reference count.
Both of these approaches will assign an instance without keeping a strong ref-
The key thing about choosing between using a class or a struct is reference or erence to it. Use the weak keyword for one and the unowned keyword for the
value passing. If you need to store some primitives (i.e. Ints, Floats, Strings, other before a property or variable declaration. Weak reference is used when
etc.), use struct. However, if you need custom behavior where passing by you know that a reference is allowed to become nil whereas unowned refer-
reference is preferable (so that you refer to the same instance everywhere), use ence is used when you are certain that the reference has a longer lifecycle and
class. will never become nil. Since weak references can have a value or no value at
all, they must be defined as optional variables. An unowned reference has to
Red flag: A red flag for this kind of question would be saying that you don’t
be defined as non-optional since it is assumed to always have a value.
really use structs and you prefer classes everywhere, just like in good old
Objective-C. Structures is a great modern addition to Swift that, just like strong Another important gotcha is Strong Reference Cycle in Closures. When you
typing, let/var, and Optionals, forces developers to think harder about the use closures within a class instance they could potentially capture self. If
data they use in their apps. self, in turn, retains that closure, you’d have a mutual strong reference cy-
37 38
cle between closure and class instance. This often occurs when you use lazy The strong, weak andassign property attributes define how memory for a
loaded properties for example. To avoid it, you’d use the same keywords weak property will be managed. It is going to be either strongly referenced, weakly
and unowned. When you define your closure, you should attach to its defi- referenced (set to nil if deallocated), or assigned (not set to nil if deallo-
nition a so called capture list. A capture list defines how the closure would cated).
handle references captured in it. By default, if you don’t use a capture list,
One great feature of Objective-C properties that is often overlooked is Key
everything will be strongly referenced. Capture lists are defined either on the
Value Observation (KVO). Every Objective-C property can be observed
same line where the closure open bracket is or on the next line after that. They
for changes enabling low-level Functional Reactive Programming capabilities.
are defined with a pair of square brackets and every element in them has a weak
or unowned keyword prefix and is separated from other elements by a comma. In Swift, however, properties defined with a simple let or var are strong by
The same thinking applies to a closure capture list as to variable references: default. They can be declared as weak or unowned references with the weak
define a capture variable as a weak Optional if it could become nil’ and the and unowned keywords before let/var. Swift properties in types are called
closure won’t be deallocated before then, and define a captured reference as stored properties. Unlike Objective-C properties, they do not have a backing
unowned if it will never become nil before the closure is deallocated. instance variable to store their values. They do declare setters and getters that
can be overridden, however.
Red flag: 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. Swift enforces basic dependency injection with properties. If you define a let
or var property, it has to be either initialized in the property declaration and
will be instantiated with that type’s instance or it has to be injected in a desig-
nated initializer instead. Optional properties don’t have to be initialized right
4.5 What are properties and instance variables in away or injected because, by their nature, they can be nil.
Objective-C and Swift? Also, Swift properties can’t be KVOed and instead have a greatly simplified
mechanic built in - Property Observers (willSet/didSet). The only
This could be a part of a memory management question or a standalone ques- way to have property KVO in Swift is to subclass from NSObject or its sub-
tion. It is very important to understand properties, instance variables, constants, classes.
and local variables when working with Objective-C and Swift because they de- Class or type properties are the properties defined for the entire type/class rather
fine how you refer to and work with your data. than individual instances of that type. In Swift, they can be defined with the
Expected answer: Properties in Objective-C are used to store data in in- static keyword for value types (struct, enum) and with the class keyword
stances of classes. They define the memory management, type, and access for class types. In Objective-C, since Swift 3 and Xcode 8, you can also define
attributes of the values they store such as strong, weak, assign, readonly class properties using the class keyword in property declaration.
and readwrite. Properties store values assigned to them in an instance vari- Properties in both Swift and Objective-C can be lazy loaded. In Swift, you’d
able that, by convention, has the same name as the property but starts with an use @lazy directive in front of a property declaration. In Objective-C, you’d
underscore prefix. When you declare a property in Objective-C that declaration have to override property getter and set and initialize its value only if the un-
will also synthesize it, meaning create a getter and setter to access and set the derlying instance variable is nil.
underlying instance variable.
39 40
Red flag: You don’t have to go too deep into the details of properties imple- Protocols are a great addition to any OO language because they allow you to
mentations and features in Swift and Objective-C. Nonetheless, you do have to clearly and explicitly declare interfaces of things in your code and be able to
know at least the basics of strong/weak/unowned referencing. rely on them. It is a way to abstract internal implementation details out and care
about types rather than about inheritance structures. Declaring clear protocols
allows you to dynamically change objects that conform to the same protocol at
runtime. It also lets you abstract things out and code against interfaces rather
4.6 What is a protocol (both Obj-C and Swift)? than specific classes or other types. It helps, for example, with the implementa-
tion of core Cocoa Touch design patterns such as Delegation. Also, develop-
When and how is it used? ing against protocols could help with test-driven development (TDD) because
stubs and mocks in tests could adopt the necessary protocols and substitute or
Protocols are vital for any strongly typed OO language. Both Objective-C and “fake” the real implementation.
Swift use them and you should expect to be asked about them on every iOS Red flag: Protocols are one of the fundamental features of Objective-C and
interview. You have an option to either just quickly go over the functionality Swift. Being able to not only use and adopt existing protocols that Cocoa
and purpose of protocols or to steer your conversation to a deeper discussion of Touch provides but also create your own is crucial for any iOS developer.
protocol-oriented programming. It’s up to you.
Expected answer: Protocols (or, in other languages, Interfaces) are dec-
larations of what a type that adopts them should implement. A protocol only
has a description or signature of the methods, properties, operators, etc. that a
4.7 What is a category/extension? When is it used?
type implements without the actual implementation.
Categories and extensions are super-useful when developing with Objective-C
In both Swift and Objective-C protocols can inherit from one or more other
and Swift. Having a handle on the benefits and limitations of categories and
protocols.
extensions is an important skill so expect this question on pretty much every
In Objective-C, protocols can declare properties, instance methods, and class interview.
methods. They can be adopted only by classes. You could define methods and
Expected answer: Categories in Objective-C and Extensions in Swift
properties as optional or required. They are required by default.
are ways to extend existing functionality of a class or type. They allow you
In Swift, protocols can declare properties, instance methods, type methods, to add additional methods in Objective-C and Swift without subclassing. And
operators and subscripts. They can be adopted by classes, structs, and enums. in Swift to add computed properties, static properties, instance/type methods,
By default, everything in Swift protocols is required. If you’d like to have initializers, subscripts, new nested types, and make existing type conform to a
optional methods and properties, you have to declare your Swift protocol as protocol without subclassing.
Objective-C compatible by prefixing it with @objc. If you prefix your protocol
In Objective-C, categories are typically used to extend the functionality of
with @objc, it can only be adopted by classes.
3rd-party or Apple framework classes. You can also use them in your own
Swift also lets you provide a default implementation for your protocols with a classes to distribute implementation into separate source files or to declare pri-
protocol extension. vate or “protected” methods.
41 42
In Swift, extensions are used to extend the functionality of existing types or thing put in them unless otherwise specified. You can avoid strong reference
to make a type conform to a protocol. cycle issues by using the __block and __weak keywords in Objective-C (or,
better still, use @strongify/@weakify) and [weak self]/[unowned self]
The drawback of extensions and categories is that they are globally applied,
in Swift.
unlike protocols. This means that after you define an extension/category for a
class or type, it will be applied to all the instances of that type, even if they Blocks and closures syntax is notoriously hard to remember so if you find
were created before the extension/category was defined. yourself stuck, check out these two websites: http://fuckingblocksyntax.com/
http://fuckingclosuresyntax.com/
Neither categories nor extensions can add new stored properties.
If those domain names are offensive to you, try these more friendly alternatives:
Another important gotcha with categories and extensions is name clashes. If
http://goshdarnblocksyntax.com/ http://goshdarnclosuresyntax.com/
you define the same name from another category/extension or existing class/type
in an extension/category, you can’t predict what implementation will take prece- Red flag: The main red flag with blocks and closures is memory manage-
dence at runtime. To avoid that collision, you should namespace your methods ment. Make sure you talk about strong reference cycle and how to avoid it with
with a prefix and an underscore; i.e., something like blocks/closures.
func ab_myExtensionMethodName() where ab is your codebase’s class/type
name prefix (same convention as with the NS prefix for Cocoa’s legacy NextStep).
Red flag: Extensions/Categories used to be an advanced feature of Objective-C 4.9 What is MVC?
and Swift but not any more. The key is not to abuse them.
Oh, good old MVC. This is a fundamental design pattern Apple keeps pushing
onto iOS developers. Every single interviewer will ask a question about this.
4.8 What are closures/blocks and how are they used?
Expected answer: MVC stands for Model View Controller. It is a software
design pattern Apple chose to be the main approach to iOS application devel-
Blocks and closures are an integral part of Objective-C and Swift development.
opment. Application data are captured and represented by Models. Views are
This question used to be an advanced one for Objective-C developers but nowa-
responsible for drawing things on the screen. Controllers control the data flow
days it is a standard for both Objective-C and Swift so it is going to be asked
between Model and View. Model and View never communicate with each other
in 100% of interviews.
directly and instead rely on Controller to coordinate the communication.
Expected answer: Blocks in Objective-C and closures in Swift declare and
A typical representation of each MVC layer in an iOS application would be the
capture a piece of executable code that will be launched at a later time. You can
following:
either define them in-line or give them dedicated type names to be referenced
and used later. Blocks and closures are the first steps to multi-threading and
asynchronicity in Swift and Objective-C since they are the building blocks that • UIView subclasses (Cocoa Touch or custom) are the Views
capture work that needs to be executed at later time (a.k.a. asynchronously).
Blocks/closures are reference types and will retain/strongly reference every- • UIViewControllers and their subclasses are the Controllers
43 44
• and any data objects, NSManagedObject subclasses and similar are the you think you’ll have only one instance of a class and you make it globally
Models available across your codebase. But at some point you need to either reset it,
do something else with the data stored on it, or realize that sharing it across
MVC is a great general purpose design pattern but using it solely limits your the whole app doesn’t make sense anymore. This is when you get into trouble
architecture and often leads to notorious “Massive View Controller”. “Massive because your singleton is everywhere now and data stored in it is unreliable
View Controller” is the state of a codebase where a lot of logic and responsi- because you don’t know who might’ve changed it and when.
bility has been shoved into View Controllers that doesn’t belong in them. That Using singletons makes it hard for you to inject dependencies because with a
practice makes your code rigid, bloated, and hard to change. There are other singleton there’s only one instance of your singleton class. That prevents you
design patterns that can help you remedy this, such as MVVM and the general from injecting it as a dependency for the purposes of testing and just general
SRP principle. Even though Apple keeps telling us that MVC is everything, inversion of control architecture.
don’t be fooled by it and stick to SOLID principles. We’ll talk more about
Red flag: Never say that singletons are good for global values and storages.
MVC, MVVM, SOLID principles, and design patterns in general in Chapter 8.
Architecting your apps this way leads to a disaster.
Red flag: You absolutely have to know what MVC is. It’s basic to any iOS
development. At the same time, though, explore alternatives and additions
such as MVVM.
45 46
4.12 What is KVO (Key-Value Observation)? stand an iOS app’s overall behavior in the system.
Expected answer:
KVO is one of the core parts of Cocoa Touch and is used widely across the
The main point of entry into iOS apps is UIApplicationDelegate.
platform.
UIApplicationDelegate is a protocol that your app has to implement to
Expected answer: KVO stands for Key-Value Observation and provides me- get notified about user events such as app launch, app goes into background or
chanics through which you can observe changes on properties in iOS. In con- foreground, app is terminated, a push notification was opened, etc.
trast to Delegate KVO entails a one-to-many relationship. Multiple objects
Lifecycle methods:
could subscribe to changes in a property of another object. As soon as that
property changes, all objects subscribing to it will be notified. (see a picture on the next page)
Under-the-hood implementation uses instance variables defined with properties
to store the actual value of the property and setters/getters supplied by synthe-
sization of those properties. Internally, when you assign a property it will call
willChangeValueForKey: and didChangeValueForKey: to trigger the
change broadcast to observers.
Another way that KVO is used in iOS apps is public broadcasting of mes-
sages through NSNotificationCenter. The underlying mechanics are the
same as with property KVO but the broadcasting can be triggered via a post:
method on NSNotificationCenter default center rather than a property change.
Originally an Objective-C feature, this is also available in Swift to classes sub-
classed from NSObject.
KVO on its own is a fairly bulky technology but it opens up a lot of possibilities
that you can build on. There are a lot of great FRP projects like ReactiveCocoa
and RxSwift that were built using KVO mechanics.
47 48
When an iOS app is launched the first thing called is
application: willFinishLaunchingWithOptions:-> Bool. This
method is intended for initial application setup. Storyboards have already been
loaded at this point but state restoration hasn’t occurred yet.
Launch
Termination
49 50
Both application: willFinishLaunchingWithOptions: and • get lifecycle callback for the view that the VC is managing (when the
application: didFinishLaunchingWithOptions: can potentially be view was loaded, displayed, hidden, etc.)
launched with options identifying that the app was called to handle a push no-
tification or url or something else. You need to return true if your app can • get handy built-in system integrations to present and dismiss VCs using
handle the given activity or url. UINavigationController, modal presentation, or parent/child con-
tainment API
51 52
• loadView(): you can override this method if you’d like to create the • viewDidDisappear() is called after viewWillDisappear and indi-
view for your VC manually. cates that the view is “hidden”.
• viewDidLoad(): this method is called once when your VC’s view was • didReceiveMemoryWarning() is called when the system is low on
loaded in memory for the first time. Do any additional setup and initial- memory and needs to release additional resources. Deallocate as much
izations here. Typically, this is the method where most of your custom as you can here. Don’t go crazy about it, though, because nowadays
view initialization and autolayout setup will go. Also, start your services phones are so powerful that memory warnings rarely happen.
and other async data-related stuff here.
Additionally, View Controller, just like Views, can be initialized either pro-
• viewWillAppear(): this method is called when the view is about to grammatically in code using init... constructor/initializer methods or loaded
appear on the screen. It will be called after viewDidLoad and ev- from a storyboard/xib file. In the former case, one of the initializer methods
ery subsequent time after view disappears from screen and then appears will be called and in the latter it will be via -initWithCoder.
again. For example, when you present a view in a navbar it will call
viewDidLoad and then viewWillAppear/viewDidAppear for that Red flag: As with memory management, you simply have to know this stuff to
VC. Later, if you push a new VC on top of it, viewWillDisappear be able to develop iOS apps.
and viewDidDisappear will be called because it’s no longer the fore-
ground/top VC. Later still, if the user taps the Back button, viewWill-
Appear and viewDidAppear for that first VC will be called because it 4.15 Conclusion
becomes the top VC again. Use this method to do final UI customiza-
tions, hook up UI observers, etc. You’ll encounter fundamental questions on every interview in various forms.
These are the basic questions and answers that it is absolutely necessary to
• viewWillLayoutSubviews() is called right before layoutSubviews()
know and understand in order to do iOS development.
in underlying UIView for that VC. It is rarely used to adjust your view
positioning.
• viewDidAppear(): this method is called right after the view was shown
on the screen and follows a viewWillAppear call.
53 54
• What is NSURLSession? How is it used?
Chapter 5 • How do you serialize and map JSON data coming from the backend?
• What is RestKit? What is it used for? What are the advantages and
Virtually every iOS app does some kind of networking. It’s an integral part of disadvantages?
our lives in this interconnection age of ours. Therefore it’s 100 percent guar-
anteed you’ll be asked the questions covered in this chapter at every interview • What could you use instead of RestKit?
you go on. The depths and details may vary, but overall, every iOS devel-
• How do you test network requests?
oper should know how to handle networking and parse JSON data and how to
structure iOS as a client-side app in general.
Alright, without further ado, let’s dive in!
5.1 What is HTTP?
Interview questions covered in this chapter:
Even though you could think that this is a purely backend question, it is very
• What is HTTP? beneficial and even necessary for iOS developers to know what HTTP is and
know the meaning of the verbs used with it. You won’t be tested on theory
• What is REST? and the history of HTTP but you should be able to talk about the basics of the
protocol that powers the modern-day web.
• How do you typically implement networking on iOS?
Expected answer: HTTP stands for Hypertext Transfer Protocol and is the
• What are the concerns and limitations of networking on iOS? foundation of today’s internet. What it means for us iOS developers is that
when we build client-side applications we connect with backend APIs via HTTP.
• What should go into the networking/service layer? When we send requests to HTTP APIs we use “verbs” such as HEAD, GET,
55 56
POST, PATCH, PUT, DELETE, etc. Each verb represents a different type of ac- 5.2 What is REST?
tion you’d like the backend to do. You’d typically work with the following
verbs in a properly implemented API: REST stands for Representational State Transfer. REST is an API architecture
built on top of HTTP protocol. Its main focus is resources and the ability
• HEAD returns header information about a resource. Typically it has a of client applications to access, write, delete, and alter them. As far as iOS
status code (200, 300, 400, etc.) and caching details. developers are concerned, it is the most popular API architecture for third-party
services and many internal product APIs. Knowing what REST is and what it
• GET returns actual data for the resource you requested. Typically it’s your means is vital for iOS app development.
domain model data. Expected answer: REST is an API architecture that revolves around resources
and HTTP verbs. Each resource is represented by a set of endpoints that can
• POST is used to, well, post something to your server. Typically used to receive some of the HTTP verb requests to do various CRUD(Create, Read,
submit data only. Update, Destroy) operations. For example, let’s say you have an API that lets
you manage posts users create in your app. A typical CRUD REST API for
• PATCH is used to change a resource’s data. Unlike PUT, it changes only
it would look like this:
certain values for the resource instead of overriding the whole thing.
• PUT is like PATCH, but instead of altering only certain values in a re- • https://yourawesomeproduct.com/posts accepts GET requests and
source, it is supposed to replace everything about the resource with the returns a list of posts available on the server.
data you submit leaving only the unique ID intact.
• https://yourawesomeproduct.com/posts/123 accepts GET re-
• DELETE, not surprisingly, destroys a resource on the backend. quests and returns a single post with given ID (123) available on the
server.
iOS applications that communicate with server APIs using the above verbs can • https://yourawesomeproduct.com/posts accepts POST requests
achieve most of the networking goals, except real-time connection/sockets, as to create new post objects with the data provided by the iOS client ap-
long as the APIs adhere to HTTP standards and respect the meaning of those plication.
verbs. It is incredibly difficult to work with a backend that does some data
changes on POST requests and returns some data on PUT requests and so on. • https://yourawesomeproduct.com/posts/123 accepts PATCH re-
Contracts between server and client were made for the purpose of not only quests to alter certain data in a specific post with a given ID.
convenience but consistency and predictability.
• https://yourawesomeproduct.com/posts/123 accepts PUT re-
Red flag: Not knowing what HTTP is. Today’s developers working with the quests to replace an entire set of data in a specific post with given ID.
web (and yes, as an iOS developer you do work with the web through requests
to server APIs) simply can’t afford not to know the fundamental meaning of • https://yourawesomeproduct.com/posts/123 accepts DELETE
HTTP verbs and the expected server behavior when using them. requests to destroy a post with a specified ID.
57 58
RESTful APIs are also supposed to return the right status codes in response to • an APIClient object that can be configured with a networking manager
your requests, such as 200 for a successful GET request or 201 for a successful to actually perform HTTP requests against your API domain. APIClient
POST request. usually is responsible for signing every request with authentication to-
ken/credentials.
If the API you’re using is truly RESTful then it will be predictable and easy to
work with. Again, protocols and contracts in software development were made • a set of service objects that work with individual resources of your
not only for convenience but for reliability as well. RESTful API such as PostsService, UsersService, etc. These ser-
Red flag: You should have at least a basic idea of what REST and RESTful vice objects use shared APIClient to issue specific concrete HTTP re-
backends are. quests to their respective /posts and /users endpoints. They compose
params and other necessary data for requests.
5.3 How do you typically implement networking At the end of the day, all other parts of the app are working directly only with
service objects and never touch low-level implementation such as APIClient
on iOS? or NSURLSession/AFNetworking/Alamofire. That separation of con-
cerns ensures that if your authentication or individual endpoints change they
This is a general networking question that could prompt and imply either a won’t affect each other in your codebase.
big picture architectural discussion about decoupling and single responsibility Red flag: Simply saying that you use NSURLSession and issue requests in
around APIs on iOS or a specific, tactical discussion about how you would view controllers when necessary isn’t gonna cut it. These days, AFNetworking
implement a networking/service layer in your applications. It’s up to you where and Alamofire are the de facto standard for doing HTTP networking on iOS
to steer the discussion. and following the Single Responsibility Principle (SRP) is vital for codebases
Expected answer: Networking falls into the service layer of your ap- big or small.
plication since it deals with external communication. In general, you should
decouple everything HTTP/network-related in your app into a set of service
and client objects that handle all the nitty-gritty of HTTP connection. Those 5.4 What are the concerns and limitations of net-
objects would perform requests and API calls for your application, decoupling
it from other layers of responsibility (like storage, business logic, UI, etc.) of
working on iOS?
the app.
The aim of this question is to gauge your understanding of the constraints of
A typical small “starter” implementation of a service layer in your app could
networking on iOS.
look like this:
Expected answer: The main networking constraints on iOS are battery and
bandwidth. iOS devices have limited battery capacity and sporadic network
• a networking/HTTP manager of some kind (either NSURLSession or connection that can drop in and out frequently. When developing the network-
AFNetworking/Alamofire manager). ing layer of the app, you should always issue as few HTTP requests as possible
59 60
and retry requests if they suddenly fail due to a poor connection or other issues. • BLEClient object that owns and manages CBCentralManager and ex-
ecutes low-level connection to BLE peripherals
There’s also a bandwidth issue; it is not a good idea to upload or download
large files and chunks of information when using a cellular connection and it is
• PeripheralsClient object that discovers peripheral services, charac-
advised to use Wi-Fi instead.
teristics, and executes low-level stuff to get and send values to and from
peripherals
5.5 What should go into the networking/service layer? • SpecificDeviceService that uses both BLEClient and Peripherals-
Client to orchestrate a connection to BLE, discovery, and communi-
This is a conceptual and architectural question. Every application consists of cation with the specific device/peripheral you’re trying to connect to.
several layers of responsibility and the service layer is responsible for all the SpecificDeviceService is also responsible for mapping data received
external data communication. You are asked about this to gauge your level of from Characteristic to your custom objects.
understanding of what is going to the service and networking layer in iOS apps
according to SRP. • CustomCharacteristicData is just like Post. In the case of JSON
Expected answer: Every iOS app that works with external data has a service API it is a domain model object that is mapped from raw data received
layer that is responsible for communication with things like HTTP APIs, GPS from BLE to conveniently work with that piece of data throughout your
location, BLE peripherals, Gyroscope, iCloud, sockets, and so on. They are application.
all external to your app resources, and to work with them, you need a set of
objects that can communicate with those resources (for example, HTTP Client As you can see, both the HTTP and BLE examples are similar in what they
or BLE manager) and can serialize/deserialize data sent to or received from do. Both of those examples wrap some kind of external service (HTTP or
those resources. BLE respectively) and make it convenient and easy to work with those exter-
Here is a typical service layer that does networking with some kind of API: nal services. At the end of the day, your application is going to interact only
with PostsService and Post objects to do its API networking, and with
• APIClient object that has an HTTP manager SpecificDeviceService and CustomCharacteristicData objects to
work with external BLE devices. Low-level implementation details like HTTP
• PostsService object that owns APIClient and issues requests to spe- GET/POST requests and BLE connection, peripheral, and characteristics dis-
cific endpoints to POST and GET posts. PostsService maps JSON covery, are all hidden behind those class interfaces. This design makes the
data to your custom domain model objects. code robust and reliable and separates low-level, unimportant logic from the
• Post class that subclasses from MTLModel to map JSON received by business logic of your app.
PostsService to your custom Post objects Red flag: Simply saying the service layer has only an HTTP client and you
create HTTP requests “when needed” for each endpoint isn’t a red flag per
And here’s what will go in the same service layer for Bluetooth Low Energy se, but you should show a deeper architectural understanding of separation of
(BLE): concerns in iOS apps.
61 62
5.6 What is NSURLSession? How is it used? based API, which means there are two ways you can issue HTTP requests with
NSURLSession: either by receiving a completion handler block callback or by
That’s one of the basic iOS networking questions. Go into deep details only if implementing delegate methods and receiving notifications as the data comes
asked. in. Either way is fine and has a different purpose depending on your use case
(for example, if you’d like to receive download progress notification you would
Expected answer: Since iOS 7, NSURLConnection became obsolete and the want to implement delegate callbacks rather than a completion block). Also
new Apple standard for implementing HTTP networking is NSURLSession. NSURLSession allows you to resume, cancel, or pause networking task.
NSURLSession and related classes do a lot of heavy lifting for basic HTTP
connection and authentication for you. It allows you to send HTTP verb (GET, All and all, NSURLSession is a very robust way of doing HTTP and other net-
POST, etc.) requests, connect to FTP, and to download files. You can option- working but in reality, it is a bit too low level, and in the majority of the cases,
ally configure cache and execute your requests in a background/app suspended you’re better off using a wrapper library like AFNetworking or Alamofire.
state. Overall the structure of NSURLSession-related things looks like the Both of them are the de facto standard for networking on iOS, and use NSURL-
following: Session under the hood to run HTTP requests for you.
Red flag: Even though these days we all use AFNetworking and Alamofire,
it is beneficial to know what’s going on under the hood and how conceptually
NSURLSession works.
63 64
validation. With it, you can setup HTTP request headers, params, issue HTTP get away with not knowing about them only if you’re very good with NSURL-
GET/POST/PUT/etc. requests, serialize JSON response, do basic HTTP au- Session.
thentication, upload and download files, and more.
Alamofire has a block-based API. You use it either directly with minimal setup
by creating requests using Alamofire class methods or by creating a session
manager object (and providing it with URLSessionConfiguration) that can 5.8 How do you handle multi-threading with net-
take callback blocks. working on iOS?
Here’s an example of a typical minimal setup request:
Multi-threading is very important when you work with networking on mobile
Alamofire.request("https://httpbin.org/get").responseJSON { response in devices. Blocking the main thread, making your UI unresponsive for the du-
print(response.request) // original URL request
print(response.response) // HTTP URL response ration of HTTP requests for a long time, is not an option. This question most
print(response.data) // server data likely will be asked in every interview in one form or another.
print(response.result) // result of response serialization
65 66
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ {
post: {
NSURLRequest *request = [NSURLRequest requestWithURL: title: 'This is an awesome post!',
[NSURL URLWithString:@"http://smartcloud.io/"]]; body: 'loads of text .....',
NSURLResponse *response; tags: ['Awesomeness', 'Coolness', 'Greatness!'],
NSError *error; }
NSData *data = [NSURLConnection sendSynchronousRequest:request }
returningResponse:&response
error:&error];
if (error) {
// handle error Then a serialized object from it is going to look like this:
return;
}
dispatch_async(dispatch_get_main_queue(), ^{ var post = Dictionary<String, AnyObject>();
// update your UI safely
}); post["title"] = "This is an awesome post!" as AnyObject?
}); post["body"] = "loads of text ....." as AnyObject?
post["tags"] = ["Awesomeness", "Coolness", "Greatness!"] as AnyObject?
print(post)
Red flag: These days every developer should know that you shouldn’t block ========== print output
the main thread with background operations such as HTTP networking. Not ["tags": <Swift._SwiftDeferredNSArray>(Awesomeness, Coolness, Greatness!),
"body": loads of text .....,
explaining what the issue is will definitely raise a red flag. "title": This is an awesome post!]
Obviously in the example above we’ve manually created the dictionary our-
5.9 How do you serialize and map JSON data com- selves but this is exactly what something like NSJSONSerialization would
do for you. NSJSONSerialization is the go-to tool for JSON dictionar-
ing from the backend? ies/arrays/primitives serialization.
Data serialization is only the first piece of the puzzle when working with JSON
JSON serialization and mapping are common tasks when you’re doing HTTP
data. The other piece is data mapping. Even though we now have a serial-
networking with an API on iOS. Expect this question either as a standalone one
ized Dictionary object that represents the post data that we’ve received from
or as a part of other HTTP/networking questions and follow-ups.
the backend, it’s still just a Dictionary and is a poor choice for us to work
Expected answer: Every time you receive JSON or XML or any other kind with throughout the app. We need a better domain model object and this
of response from a backend API, you most likely get it in a JSON or binary is where data mapping comes into play. In order for us to work with our own
or other “inconvenient” format. The first thing you need to do to be able to custom domain model objects and classes, that dictionary needs to be mapped
work with the data you’ve received is to serialize it in something your app into those custom classes. You can either do it yourself manually, take a Dic-
understands. At the most simplest and basic level that would be a dictionary or tionary object, take values for each key and assign them to properties on your
array of objects containing other dictionaries, arrays, and primitives from that custom Post class or struct object. But that is a very tedious and error-prone
response. So let’s say if your JSON response looks like this: boilerplate code. A better solution for this would be a library such as Mantle or
67 68
ObjectMapper. Both of those help you declare your key/property mapping and images for given URLs, along with placeholder images and download progress
automate the process. As a result you’d get your custom domain model objects reporting.
crafted specifically for the tasks your application does, reducing errors.
Red flag: Too many developers neglect proper data mapping in their applica-
tions. Understanding what serialization and mapping are, what the differences
are between them, and why it is important to have well-defined domain models
will set you apart from other devs.
69 70
5.12 How do you download files on iOS? 5.13 Have you used sockets and/or pubsub systems?
File download is a common task for iOS apps. It could be a PDF or image or This question isn’t typical for most of teams and companies, but those that work
video file that you need your app to download. And as usual, this question gives with messaging/chat applications are most likely going to ask it. Pub/sub sys-
you an opportunity to either go over the basics or to dig deeper and explain the tems are growing in popularity for solving problems other than chat/messaging
different techniques there are for downloading files. on iOS though, so it is beneficial for iOS developers to be at least familiar with
Expected answer: At the very basic level, file download is just fetching a the topic.
bunch of bytes from a URL over HTTP somewhere on the web. Either NS- Expected answer: Sockets is a specific technology for persistent connection
URLSession’s NSURLSessionDataTask or Alamofire’s download GET communication and you can think of it as a subset of pub/sub systems. Sockets
request will do the trick. When you get the data there are three ways you can and pub/sub systems such as Pubnub allow you to build apps that can connect
deal with it. You either: 1. work with received data right there in-memory in and observe external data streams and react and process received data in nearly
the callback where you received it, 2. store the received file in a temporary real time.
folder for later use, or 3. store the received file permanently on the disk.
Consider this example: you’re building an app similar to Facebook Messenger.
In that app you have your normal view controller with a list of chats you have
1. Working the file right after you received it is the easiest. You have it open and when you open a specific chat it will open another view controller
in NSData form and it’s accessible without any further ceremony. The for that chat. This new view controller with a specific chat then subscribes to
disadvantage though is that you can work with only small size files in a channel using sockets or Pubnub or another pubsub system. As soon as it’s
that fashion. If a file is too big, it could take too long to download and be subscribed to its chat channel, it will receive the latest batch of messages since
too expensive to handle in the callback block. the last connection and then will start receiving and sending new messages in
real time as participants of that chat type them. That is the general idea of how
2. Storing the received file in a temp folder is a mid-ground solution that chat/message applications work.
typically is the best compromise and a great way to handle the data you
just downloaded. Storing it in a temp folder allows you postpone han-
dling the file until a later time and lets you move on in your download
callback block. Files are kept in the temp folder only for the duration of 5.14 What is RestKit? What is it used for? What
your app running, though. are the advantages and disadvantages?
3. Storing the received file on disk allows you to access it later and some-
times is the only way to handle downloaded files when they are too big RestKit used to be a very popular data synchronization framework used by
to operate on in the download callback block. many companies, especially with legacy codebases. It is not as popular these
days, but if you’re joining a team that has to support that legacy technology,
then expect to be asked about RestKit.
Red flag: You should have at least a basic understanding of how to download
files on iOS. Expected answer: RestKit is a framework that was made for the purpose of
71 72
data synchronization between client iOS applications and RESTful web ser- 5.15 What could you use instead of RestKit?
vices. RestKit has several responsibilities it takes onto itself such as
Since RestKit is practically obsolete these days, you could be asked about al-
ternatives you could use instead of RestKit to synchronize data with backend
• HTTP url composition and building (routing), APIs.
Expected answer: You have several options instead of RestKit to use for data
• HTTP GET/POST/etc. request sending and enqueueing,
synchronization with backend APIs:
• JSON request and response serialization,
• Overcoat
• JSON response parsing and mapping, • Roll-Your-Own-Solution
• Core Data synchronization with mapping from JSON domain models Overcoat is another library that takes care of a lot of things for you like RestKit,
received from the backend, but unlike RestKit its API is way easier to use. It takes care of routing, HTTP
requests, JSON response parsing, object mapping from JSON to custom ob-
• POSTing/PUTing/etc. domain models created locally and synced with jects, object mapping from custom objects to Core Data, and promises API out
Core Data with a remote RESTful service. of the box. It takes on a lot of responsibilities just like RestKit and therefore is
not advisable to use for every app.
But the better option is to roll your own solution. If you think about it, every-
As you can see it takes on quite a lot. thing that RestKit does is more or less necessary for any complex enough iOS
At the end of the day the reason RestKit became obsolete and is virtually not application. Things that it does can be implemented using other libraries and
used anymore on new projects is because it was doing too much for you and tools available. For example:
forced you into its convoluted API. RestKit is so big that entire book can be
written about it. If you want to learn more or unfortunately have to support it • HTTP URL composition/routing can be implemented as a simple custom
on a legacy project, head over to restkit on github to dig deeper into it. URL builder.
As an alternative to RestKit, you’re better off rolling your own solution for data • HTTP GET/POST/etc. requests sending and enqueueing can be handled
synchronization. RestKit’s downfall was that it broke SRP. Choose wisely what by AFNetworking and Alamofire.
features and functionality you need from your libraries and how they should be
used in your applications. • JSON request and response serialization is taken care of by NSJSON-
Serialization and/or Alamofire/AFNetworking.
Red flag: You don’t have to have experience with RestKit these days, but it is
very beneficial to have a general understanding of what it offers and does for • JSON response parsing and mapping can be handled by a library like
you so that you can make a conscious decision to pick it or avoid it. Mantle.
73 74
• Core Data synchronization and mapping from/to custom domain models
can be taken care of by Mantle.
And that’s everything you need. Rolling your own solution, and only when you
need to, will also help you evolve your codebase gradually without introducing
things with unnecessary functionality and baggage. You just need to know what
you need.
5.17 Conclusion
Service- and networking-related questions are 100 percent guaranteed to be
asked on every iOS interview. Networking is the building block of pretty much
any iOS application these days; this is what makes apps useful - the ability to
connect to external services and the internet. In order to be a good iOS citizen
and create efficient apps that don’t waste bandwidth and sync data just in time,
you should know your options and know what you really need to accomplish
your task.
75 76
• What is NSCoding?
• What is NSUserDefaults?
Step Five: Learn How to • How is data mapping important when you store data?
This chapter covers storage layer questions and answers and is good for quick
6.1 What is the storage layer for in iOS applica-
interview prep for those questions. But there’s more to it and the coverage tions?
in this chapter is continued in a bonus chapter, Chapter 9 Storage Evolution
(AKA You Don’t Always Need Core Data!). where we walk through building This is a broad, open-ended question that could be asked in many forms. Ef-
a small storage layer. We start with an in-memory array and then evolve and fectively your interviewer is trying to gauge how you work with data, state, and
refactor it to use NSUserDefaults, File/Disk storage, and eventually Core persistence in iOS applications.
Data, looking at advantages and disadvantages of each along the way.
Expected Answer: The storage layer is responsible for storing data and keep-
The storage layer is present in every application because all of them need to ing track of state. Objects and classes in this layer perform storing, saving,
have a state in one form or another. Often apps need to persist that state as persisting, and mapping/serialization operations on data that other layers of the
well. This is why it is important for iOS devs to know storage options. In this apps, such as the service layer, provide. At the end of the day you’ll have
chapter we’ll cover questions about arrays and dictionaries, NSUserDefaults, things as simple as in-memory arrays and dictionaries and as complex as your
file disk storage, Keychain, database solutions such Core Data, and more. own custom model objects and Core Data and Realm databases in this layer.
Interview questions covered in this chapter: The main point is that this layer decouples everything related to data storage
and persistence from other classes and layers of your application.
Here’s a typical set of classes that you’d have in your storage layer:
• What is the storage layer for in iOS applications?
• What can you use to store data on iOS? • a wrapper around Keychain
77 78
• a wrapper around NSUserDefaults • NSUserDefaults/Keychain
• NSManagedObjects and its subclasses used to persist your domain model • SQLite
objects to Core Data (if you use Core Data)
• Post custom domain model class that represents instances of each post
in your application In-memory arrays, dictionaries, sets, and other data structures
are perfectly fine for storing data. They are fast and simple to use. The main
• PostsStorage object that initiates storing/fetching of Post models us- disadvantage though is that they can’t be persisted without some work and can’t
ing a repository object and mapping its NSManagedObject results be used to store large amounts of data.
to Post model objects
NSUserDefaults/Keychain are simple key-value stores. One is insecure
and another one is secure respectively. Advantages are that they are easy to use,
Red Flag: This is not really a red flag, but quite often developers think that relatively fast, and are actually able to persist things to disk. Disadvantages are
only Core Data or Realm belong in the storage layer. In fact, you don’t have to that they were not made as a replacement for databases and can’t handle large
use either of those technologies, and sometimes a simple in-memory array of amounts of data or extensive querying.
objects will suffice. Use only what you need in your specific context.
File/Disk storage is actually a way of writing pieces of data (serialized
or not) to/from a disk using NSFileManager. The great thing about it is that
it can handle big files / large amounts of data but the disadvantage is that it was
6.2 What can you use to store data on iOS? not made for querying.
Core Data or Realm are frameworks that simplify work with databases. They
Interviewers ask this question to grasp your understanding of what tools and are great for large amounts of data and perfect for querying and filtering. Dis-
ways you have available to store and persist data on iOS. advantages are the setup overhead and learning curve.
Expected Answer: Generally there are the following ways to store data in Red Flag: You should be aware of different ways you could store data on iOS
order from simple to complex: 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
• In-memory arrays, dictionaries, sets, and other data structures over the other.
79 80
6.3 What is NSCoding? A typical use case for it is some locally stored user preferences and/or flags.
Do not use it as a database replacement because it was not built for extensive
NSCoding is a widely used protocol for data serialization necessary for some querying or for handling large amounts of data.
of the data-storing operations using NSUserDefaults, NSFileManager, and Red Flag: Using user defaults for data that needs to be secure is a red flag. For
Keychain. Interviewers will most likely ask this as part of a discussion about example, you would never want to store a user’s password or access token in
storage options on iOS, NSUserDefaults, Keychain, and so on. user defaults; use Keychain for that instead.
Expected Answer: NSCoding is a Cocoa protocol that allows objects that
adopt it to be serialized for NSUserDefaults, NSFileManager, or Keychain
storage. The way it works is you implement the init?(coder decoder: 6.5 What is Keychain and when do you need it?
NSCoder) and encodeWithCoder methods in the objects that comply to that
protocol. Those methods decode and encode the object respectively for persis- Storing data securely is important for every iOS app, big or small. This ques-
tence and retrieval. tion is assessing your experience with iOS secure key-value storage.
The gotcha with implementing NSCoding is that every property that you en- Expected Answer: Keychain is a secure alternative to NSUserDefaults. It
code and decode needs to comply to the NSCoding protocol as well. All the is a key-value store that is encrypted by the system and persists between app
“primitive” values such as String, Number, and Int already do that and ev- reinstalls unlike other types of data such as NSUserDefaults, files on disk,
ery custom object that you’re trying to serialize as one of the properties needs and Core Data databases. The advantage of Keychain is that it is secure, but
to comply to that protocol as well. the disadvantage is that its API is difficult to use.
Red Flag: NSCoding is one of the fundamental protocols to use “lightweight” The main use case for Keychain is to store small objects and primitives, such
persistence implementation in iOS applications. Every iOS dev should be fa- as tokens and passwords, securely. Use it instead of NSUserDefaults for
miliar with it. that purpose, and just like with NSUserDefaults do not use it to store large
amounts of data, such as databases, images, and videos.
Red Flag: You should be familiar with Keychain and what it’s used for. The
6.4 What is NSUserDefaults? main red flag would be to either say that you use it instead of NSUserDefaults
or vice versa. Both have their own purpose.
NSUserDefaults is one of the common tools used in virtually every appli-
cation for lightweight storage. Every iOS developer should be familiar with
it. 6.6 How do you save data to a disk on iOS?
Expected Answer: NSUserDefaults is a key-value storage that can persist
serialized NSCoding compliant objects and primitives. Unlike Keychain, it is Storing files on a disk is a more or less common thing to do in iOS applications.
not secure and does not persist between app uninstalls. It’s main purpose is to Don’t expect this question that often, but note that it could come up from time
store small objects that are easily retrievable but also not important to lose. to time in the context of storage.
81 82
Expected Answer: File storage is used to persist large amounts of data on a forward addition on top of a relational database where each object represents a
disk such as images, videos, and other kinds of files. NSFileManager is the row in a table (like in ActiveRecord, for example), but rather an object graph
class you would use to manipulate you app’s folder on a disk. It is capable of storage.
creating subdirectories and storing files. You can store or read any NSData ob-
Realm is an alternative to the Core Data database solution. It was built from
ject whether it’s an image, video, or an object serialized through the NSCoding
the ground up to be easier to use and faster than Core Data or SQL. Advantages
protocol.
of Realm are that it’s fast, has reactive features, is easier to use, is secure, and
Red Flag: There isn’t a specific red flag for this question. File disk storage is has entire cloud platform for syncing and other more advanced features. A
often not used directly because these days there are a lot of libraries and pods disadvantage is that it is still in development - although the Realm team made
that take care of that low-level detail for you. But as a good iOS dev you need a lot of progress recently - and as of the time of this writing, it doesn’t have
to be familiar with NSFileManager and how you can use it to persist stuff on all the features on par with Core Data’s NSFetchedResultsController.
disk. There are also issues with the size of realm databases. Due to their playback
feature, it has to store way more data to replay the events that happened as
compared to Core Data or SQL, which stores only the latest snapshot without
6.7 What database options are there for iOS ap- keeping a history of all the changes.
plications? Realm has a lot of potential to become the most popular solution for database
storage on iOS in the long run, especially with all the backend/syncing func-
tionality they are building into it.
Interviewers ask this question to gauge your experience with database solutions
on iOS. SQLite is a relational database that powers Core Data under the hood. It can
be accessed directly on iOS and used without Core Data, but it will require
Expected Answer: The go-to database solution on iOS is Core Data. There is implementing custom tooling for accessing, reading, and writing to it. The
also an option to use SQLite directly but tools are not that advanced for that, so main advantages of using SQLite directly are that it is going to be fast, and if
you’ll have to come up with some customizations of your own. you have SQL skills you can leverage them. The main disadvantage though is
Another popular database framework is Realm. Each one of them has their own that you’ll have to do all the heavy lifting of setting things up and accessing
advantages and disadvantages. and migrating the database yourself; there are no good tools out there to help
with that.
Core Data is an object graph and persistence framework that is the go-to solu-
tion for local database storage on iOS. Advantages of that framework are that it Red Flag: These days saying that there’s only Core Data on iOS for databases
is widely used and is supported by Apple. You can use it almost out of the box would raise a red flag because the expectation is that developers are constantly
in your project, and it does a decent job of persisting data and making querying looking for better solutions and are aware of other alternatives such as Realm
more or less straightforward. or SQLite.
A disadvantage is that the Core Data API is not that easy to use in some scenar-
ios and specifically in a multi-threading environment. Another big disadvan-
tage of Core Data is that there’s a learning curve to it since it is not a straight-
83 84
6.8 How is data mapping important when you store with them throughout the application. This issue is especially apparent when,
inevitably, issues with multi-threading and concurrency arise. A cleaner way
data? of doing it would be to use NSManagedObject and/or its subclasses only for
data persistence and retrieval and use your own custom objects throughout the
Interviewers will most likely ask this question as part of a general discussion application as domain models.
around the storage layer and the responsibilities it has. Just like with the ser-
Another example of similar mapping and serialization that you’ll have to do
vice/networking layer, you need to understand the vital parts of it and what
would be NSCoding protocol serialization. If you use NSUserDefaults for
functions it performs, even if they are hidden by a library or a framework you
storage of custom objects in your app then you’d need to do a similar serializa-
use.
tion step. It is not that apparent because you typically implement the NSCoding
Expected Answer: One of the three main purposes of the storage layer, be- protocol on your actual domain model objects, but effectively you go through
sides actually storing and persisting the data, is data serialization. Just like the same process of retrieving data and then mapping it to your custom objects
when you get data in the service layer in JSON or another format from exter- (or serializing your custom objects to raw data and then saving them). For
nal APIs and then serialize and map it into your custom domain model in the reading, it would look like this: NSUserDefaults -> NSData -> your
storage layer, you will need to serialize and map your data to and from your custom object. And for writing: your custom object -> NSData >
custom domain model objects to the format that your storage understands. The NSUserDefaults. The reason it is not apparent is because the NSData ->
“mapping” chain for reading data looks like this: db -> raw data format model mapping step is “hidden” thanks to the NSCoding protocol, and you get
-> custom domain models. And for writing like this: custom domain your objects back without that intermediate step. But the same argument about
models -> raw data format -> db. coupling as with Core Data’s NSManagedObject could apply, and it would
For example, that means that if you use Core Data, then serialization of your be valid. But the difference between implementing NSCoding and coupling
data that you’ll make before saving it in Core Data will be mapping it to yourself to it and inheriting from NSManagedObject is that in one case it is a
NSManagedObjects and then saving those to the Core Data database. And loose coupling to an interface and in the other case it is a tight coupling to an
vice versa, when you need to retrieve data from Core Data, you’ll create a implementation. As you’ll read in Chapter 8, according to SOLID principles,
predicate to query it and then you’ll get back a bunch of NSManagedObjects it’s always better to couple yourself as loosely as possible.
and/or their subclasses as the result. You’ll then need to map those objects into Red Flag: The main red flag for this question is not being aware of serializa-
your own custom domain model objects to be able to easily work with them. tion actually happening in the storage layer. Even if you don’t implement it
Specifically, in the case of NSManagedObjects, there are different approaches yourself explicitly, you should still be aware of its existence and of the cost
to working with data and quite often NSManagedObject subclasses are used you’re paying for hiding that implementation and coupling yourself to a library
directly as model objects throughout application. It is convenient after all to use or a framework.
them since mapping of values and properties is easily defined in the Core Data
entity schema UI in Xcode. But there’s a disadvantage to that approach that lies
in coupling of responsibilities in NSManagedObject subclasses. If you use
them throughout your application as domain models, then you couple yourself
to Core Data directly and carry all the functionality of NSManagedObject
85 86
6.9 How would you approach major database/storage we will evolve and migrate it to use NSUserDefaults, then file/disk storage,
and then eventually Core Data, keeping PostsStorage’s API consistent and
migration in your application? unchanged throughout the whole process while the rest of the app will have no
idea that we used various persistence solutions under the hood.
This question could be a part of an architectural discussion or come out of
refactoring talks with your interviewer. Typically interviewers for bigger teams
that are concerned with maintainability of the code ask this question. 6.10 Conclusion:
Expected Answer: In practice, database or underlying storage migrations hap-
pen very rarely on iOS applications. Typically codebases end up getting stuck The storage layer is one the building blocks of every iOS application. There are
with whatever they picked as the initial storage/database solution (quite often various approaches to storage and persistence when it comes to iOS apps, and
Core Data). But there’s a way you could organize your code using the Single a good developer knows what options are available and knows when to pick the
Responsibility Principle where your codebase will be completely decoupled right type of persistence solution.
and agnostic of the persistence framework you use. This chapter gives you an overview of questions and answers around storage on
The main idea is to have a clear separation between your code that needs to iOS. If you want a practical example of all of the types of storages mentioned
access and use data from the database and the code that actually knows what in this chapter, please look at the bonus chapter of this book, Chapter 9 Storage
database to use and how to access data in it. Typically that role is played by Evolution (AKA You Don’t Always Need Core Data!).
some kind of storage object that is the main object responsible for getting
data in and out of database for the rest of the application. Internally that object
would use one or more other objects that actually know how to work with
an underlying database, let’s say Core Data. And only those objects in the
storage class actually refer to Core Data and know how to query it and how
to write to it.
Since the rest of the application doesn’t know anything about Core Data or
whatever database solution you use, when the time comes, you could easily
swap the underlying database for Realm, for example. You’d have to write
some data migration code that will map and copy data from the existing Core
Data to the new Realm. But the main approach will remain the same - the rest
of your application continues to rely on the storage object to get the data and
that object knows how to actually work with it.
This decoupling and Single Responsibility approach is described in detail in the
bonus chapter, Storage Evolution. In that chapter we’ll go through an example
of the PostsStorage class that will start as simple in-memory storage, and
87 88
• What is AutoLayout? When and where would you use it?
Step Six: Go crazy • How do you work with storyboards in a large team?
Quite often, creating a UI is one of the biggest parts of an iOS project. Being
• How do you do animation with Frames and AutoLayout?
able to make it viewable on different-sized screens is a very crucial skill for any
kind of project and team. Back in the day, we were only able to do frame size
calculations and a little bit of auto-resizing masks. These days we have Auto- • How do you work with UITableView?
Layout. The problem is it is notoriously difficult to work with and especially
to debug. • How do you optimize table views performance for smooth, fast scrolling?
But there’s hope - there are libraries like Masonry that help you to declaratively
• How do you work with UICollectionView?
define your AutoLayout constraints in code.
This chapter is going to be especially useful if you’re applying for a company • How do you work with UIScrollView?
that is heavy on UI and values design a lot.
Interview questions covered in this chapter: • What is UIStackView? When would you use it and why?
• What do you use to lay out your views correctly on iOS? • How do you make a pixel-perfect UI according to a designer’s specs?
• What are CGRect Frames? When and where would you use them? • How do you unit and integration test UI?
89 90
7.1 What are the challenges in working with UI on is to quickly calculate cell and other UI elements’ sizes when the user scrolls
the content quickly. Mentioning that will most likely prompt your interviewer
iOS? to ask probing questions about Frames, AutoLayout, and UITableView/UICollectionVi
This question is typically asked to assess whether you understand that it’s not Red flag: Not mentioning various iPhone/iPad screen sizes and not mentioning
that simple and straightforward to do UI on iOS anymore. Now we have mul- AutoLayout as one of the solutions most likely is going to raise a flag.
tiple screen sizes and resolutions, not to mention iPad and Multi-Tasking sup-
port, where your views and view controllers can be displayed in various forms
and formats. 7.2 What do you use to lay out your views cor-
Expected answer: Show them that you are aware of the responsive and ad- rectly on iOS?
justable nature of iOS UI. There are several things you as a developer need to
be concerned with when developing UI for 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
• multiple screen sizes/dimensions for iPhone 5, 6, 6 Plus, etc. 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
• multiple screen sizes/dimensions for iPads it would be great to mention other options such a ComponentKit and other
Flexbox and React implementation on iOS.
• potential reusability of UIViews between iPhone and iPad
Expected answer: Go-to options for laying out views on the screen are good
• adaptability of your UI to resizable views used for multi-tasking feature old CGRect Frames and AutoLayout. Frames, along with auto-resizing masks,
on iPad (i.e., size classes) 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
• UI performance, especially with dynamic content of various sizes in
coordinates and view sizes for various devices.
UITableViews and UICollectionViews
Since iOS 6 we have AutoLayout, which is the go-to solution these days and
is preferred by Apple. AutoLayout is a technology that helps you define re-
Mentioning all of the concerns above show that you are aware of the issues.
lationships between views, called constraints, in a declarative way, letting the
Also, it is good if you mention here that Apple has AutoLayout to address a
framework calculate precise frames and positions of UI elements instead.
lot of the challenges related to UI scalability and that it is a replacement of
the previously used Frames and auto-resizing masks approach. These answers There are other options for laying out views, such as ComponentKit and Lay-
will likely make your interviewer steer toward a Frames versus AutoLayout outKit, that are more or less inspired by React. These alternatives are good
discussion. 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
Table views and collection views’ performance is especially important for so-
and knowing there are other options is always good.
cial networking applications, for example. They typically have content of arbi-
trary size posted by users that need to be displayed in lists. The challenge there Red flag: Not mentioning at least AutoLayout and the fact that Frames are
91 92
notoriously hard to get right is definitely going to be a red flag for your inter- ing that frames are perfectly fine for laying out views would raise a red flag
viewer. These days no sane person would do CGRect frame calculations unless because most likely your interviewer would think that you don’t know how to
it is absolutely necessary (for example, when you do some crazy drawings). build adaptive and responsive UI.
7.3 What are CGRect Frames? When and where 7.4 What is AutoLayout? When and where would
would you use them? you use it?
This is a very common UI-related question on any interview. Virtually no in-
This question is asked to learn if you have a background in building UI “the terview will go without it. AutoLayout is one of the fundamental technologies
hard way” with using view position and size calculation. Before AutoLayout, that Apple pushed for for some time and now it is the de facto standard. Your
Frames were used to position UI elements on the screen but these days there interviewer is either expecting a very brief answer to get an understanding of
are other options you have to solve that problem. The interviewer is trying to whether you’re versed in the topic or is going to drill down and ask you for all
figure out how advanced you are in UI rendering and how well you know a the details about it. Be prepared for both.
lower level of it.
Expected answer: AutoLayout is a technology that helps you define relation-
Expected answer: The simplest way to position views on the screen is to give ships between views, called constraints, in a declarative way, letting the frame-
them specific coordinates and sizes with CGRects. CGRect is a struct that work calculate precise frames and positions of UI elements instead. AutoLay-
represents a rectangle that a view is placed at. It has origin with x and y out came as an evolution of previously used Frames and auto-resizing masks.
values, and size with width and height values. They represent the upper- Apple created it to support various screen resolutions and sizes of iOS devices.
left corner where the view starts to draw itself and the width and height of that
view respectively. Frames are used to explicitly position views on the screen In a nutshell, using AutoLayout instead of setting view frames, you’ll cre-
and have the most flexibility in terms of what and how you position views on ate NSLayoutConstraint objects either in code or use nibs or storyboards.
the screen. But the disadvantage is that you have to take care of everything NSLayoutConstraints describe how views relate to each other so that at
yourself (with great power comes great responsibility, you know), meaning runtime UIKit can decide what specific CGRect frames to set for each view.
even though you’re in full control of how your UI is drawn on the screen, you It will adjust to different screen sizes or orientations based on the “rules” you
will have to take care of all the edge cases and the different screen sizes and defined using constraints.
resolutions. The main things you’ll be using working with AutoLayout are NSLayout-
A better option these days is AutoLayout. It helps you with layout positioning Relation, constant, and priority.
through constraints and sets specific frames for views for you. It makes your
views scalable and adaptive to different screen sizes and resolutions.
• NSLayoutRelation defines the nature of a constraint between two UI
Red flag: AutoLayout is the de facto standard for doing layouts these days. items/views. It can be lessThanOrEqual, equal, or greaterThan-
Frames are considered to be an outdated concept that is very error prone. Say- OrEqual.
93 94
• constant defines constraint value. It usually defines things like the Red flag: You should be familiar with these constraints if you worked with
distance between two views, or the width of an item or margin, etc. AutoLayout extensively.
• priority defines how high of a priority a given constraint should take.
Constraints with a higher priority number take precedence over the oth-
ers. Priority typically is used to resolve conflicting constraints. For
7.6 How does AutoLayout work with multi-threading?
example, when there could be an absence of content, we may want to
align elements differently. In that scenario we’d create several constraints Pretty much every iOS application these days has some kind of multi-threading.
with different priority. Interviewers ask this question to gauge your general understanding of how to
work with the main thread and background threads and with UI in particular.
Bonus points: Working with Apple’s API for constraints in code is sometimes Expected answer: All UI changes have to be done on the main thread. Just
problematic and difficult. There are several different open source libraries out like working with Frames, working with AutoLayout is UI work and it needs
there that can help with it, such as Masonry and PureLayout, that dramatically to be performed on the main UI thread. Every AutoLayout constraint’s addition
simplify the process. or removal or constant change needs to be done on the main thread. After you
change constraints, call the setNeedsLayout method.
Red flag: AutoLayout is the de facto standard today for developing UI on iOS.
Disregarding it or trying to prove that the Frames approach is better most likely Red flag: Saying you can change AutoLayout constraints in any thread will
going to raise a red flag. There are alternatives of course but most likely your raise a red flag.
interviewer expects you to be very familiar with the technology since it’s such
a vital part of any iOS application.
7.7 What are the advantages and disadvantages of
7.5 What are compression resistance and content creating AutoLayouts in code versus using sto-
hugging priorities for? ryboards?
Bigger teams sometimes ask this question because they experience particular
This is an advanced question about AutoLayout typically asked along with
challenges when it comes to working with UI using storyboards. There’s no
other questions around constraints.
right or wrong answer here; every approach has its advantages and disadvan-
Expected answer: Compression resistance is an AutoLayout constraint that tages.
defines how your view will behave while under the pressure of other constraints
Expected answer: Working with AutoLayout in storyboards is considered to
demanding its resizing. The higher compression resistance is, the less chance
be more typical, and Apple pushes a lot of examples showing how to do that.
it’s going to “budge” under the other constraint’s pressure to compress it.
The advantages are that it’s visual, drag-and-drop/plug-and-play-able, and you
Hugging priority is the opposite of compression resistance. This constraint can, in some scenarios, actually render your UI in Interface Builder without
defines how likely it it the view will grow under pressure from other constraints actually running the app and waiting for the entire build process to happen.
95 96
Neat. But the disadvantages are very apparent when you need to debug your 7.9 How do you mix AutoLayout with Frames?
constraints or work in a team of more than two people. It is difficult to tell
what constraints need to be there and what constraints need to be removed at This question could be asked by a team that has an existing application and
a glance. And quite often, teams working with one storyboard modify it in they are trying to either migrate to AutoLayout fully or to support both Frames
different git branches, causing merge conflicts. and AutoLayout at the same time for legacy reasons.
Also, the advantages of defining AutoLayout in code are that it’s very explicit, Expected answer: AutoLayout and Frames can coexist together only in sce-
clear, and merge- and conflict-free. Disadvantages, on the other hand, are that narios when you’re not mixing them up directly. Basically, you can have a
it’s difficult to work with Apple’s AutoLayout constraints API in code (it can superview lay out itself and its subviews using constraints and have one or all
be helped if you use a library like Masonry) and you have to compile your app of those subviews position themselves with frames. Views that need to use
to see the results of rendering. frames will have to override the layoutSubviews() method where they can
do the precise calculations for CGRects necessary to align things in them.
Red flag: Never say that you can just simply change frames of views that use
7.8 How do you work with storyboards in a large AutoLayout. That would not work because with AutoLayout, frames are set by
the system based on the constraints you’ve created.
team?
Bigger teams ask this question. They especially suffer from a poor team devel- 7.10 What options do you have with animation on
opment support from Apple tools.
iOS?
Expected answer: The main problem when working with storyboards in a big
team is dealing with .storyboard file merge conflicts. When two developers Interviewers ask this question to probe your level of experience with animation
change the same storyboard in different branches, they most likely will have on iOS. Depending on the team and project focus you could either answer
a merge conflict. The benefits a unified monolith storyboard gives are quickly briefly or extensively about each option available.
outweighed by the struggle teams experience with those merge conflicts. There
are two solutions: Expected answer: There are three major things you can use on iOS to animate
your UI: UIKit, Core Animation, and UIKit Dynamics.
1. Don’t use storyboards and define your AutoLayout in code. • UIKit is the basic animation that is used the most often. It can be trig-
gered by running the UIView.animateWithDuration() set of meth-
ods. Things that are “animatable” this way are frame, bounds, center,
2. Split your monolithic storyboard into multiple storyboards, typically one transform, alpha, and backgroundColor.
per view controller. That way, storyboard changes will happen only when
one view controller is modified, which likely will help you avoid most of • Core Animation is used for more advanced animation, things that UI-
the merge conflicts. Kit isn’t capable of doing. With Core Animation, you will manipulate
97 98
the view’s layer directly and use classes like CABasicAnimation to 7.12 How do you work with UITableView?
set up more complex animations.
• UIKit Dynamics is used to create dynamic interactive animations. These UITableView is one of the most used and important UI classes in iOS appli-
animations are a more complex kind where the user can interact with cations. You can expect this question in one form or another on pretty much
your animation half-way through and potentially even revert it. With any interview. The extent of your answer will vary, and if interviewers wants
UIKit Dynamics you’ll work with classes like UIDynamicItem. Note: to dig deeper, they’ll ask additional questions around table views.
there’s also a very handy dynamics animation library by Facebook called Expected answer: UITableView is a class that lets you display a list of static
Pop that can help with it. or dynamic content of variable or set heights with optional section grouping.
Each row in a table is a UITableViewCell class or subclass. Table views and
cells can be as complex or as simple as the application demands. Two of the
Red flag: Most likely your interviewer won’t expect you to be very familiar biggest constraints on mobile devices are memory and performance. This is
with advanced animation techniques unless you claim that you’re an expert. why table views are designed to dequeue and reuse UITableViewCells they
But nevertheless, you should be at least aware of other options beyond UIKit are displaying instead of creating new objects as user scrolls. It helps avoid
animations. memory bloat and improves performance.
When you work with UITableView you usually instantiate an instance of it
and then implement UITableViewDelegate and UITableViewDataSource
7.11 How do you do animation with Frames and protocols.
AutoLayout?
This is a more specific question about views animation. Depending on the
project and team focus they either would like to know how you handle basic • UITableViewDelegate is responsible for calculating cells’ and sec-
animations or they want to know if you know how to work with advanced tions’ heights (unless it’s done automatically with UITableViewAutomatic-
animations using Core Animation. Dimension) and for the other cell and section life cycle callbacks like
tableView(UITableView, willDisplay: UITableViewCell,
Expected answer: Most likely talking about how to animate views with UIKit
forRowAt: IndexPath) and tableView(UITableView, did-
is sufficient enough. With frame-based views you simply change frames in
SelectRowAt: IndexPath). It also dequeues section views.
UIView.animateWithDuration:animations: and then assign new frames
to your views and that’s it - the animation will be performed. It’s almost
the same thing with AutoLayout, but instead of changing frames directly you
change your constraints and their constants in the animations: block of • UITableViewDataSource is the source of data for the table. It pro-
the UIView.animateWithDuration:animations: method and then call vides the model data your table is displaying. It is also responsible for
layoutIfNeeded() on the views you’ve changed. dequeuing cells for specific indexPath.
99 100
7.13 How do you optimize table views performance Expected answer: UICollectionView is the next step from UITableView
and it was made to display complex layouts for lists of items - think a grid
for smooth, fast scrolling? where you have two or more items in a row or a grid where each item could
be a different size. Each item in a UICollectionView is a subclass of UI-
One of the important questions that is sometimes asked on interviews along CollectionViewCell. UICollectionView mimics UITableView in its
with UITableView questions is a question about table view scrolling perfor- API and has similar UICollectionViewDelegate and UICollection-
mance. ViewDataSource to perform the same functions.
Expected answer: Scrolling performance is a big issue with UITableViews A very distinct feature of UICollectionView is that unlike UITableView
and quite often can be very hard to get right. The main difficulty is cell height it is using UICollectionViewLayout to help it lay out views it is going to
calculation. When the user scrolls, every next cell needs to calculate its content display in its list.
and then height before it can be displayed. If you do manual Frame view lay-
outs 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 7.15 How do you work with UIScrollView?
• calculate cell height yourself UIScrollView is a very common UI component used in iOS apps. Interview-
ers typically ask this question to gauge your level of experience working with
• keep a prototype cell that you fill with content and use to calculate cell either big, scrollable and zoomable content or gauge your level of understand-
height ing of UITableView and UICollectionView.
Expected answer: UIScrollView is responsible for displaying content that
Alternatively, you could take a completely radical approach, which is to use dif- is too big and cannot be fully displayed on the screen. It could be a big picture
ferent technology like ComponentKit. ComponentKit is made specifically for that the user can pinch to zoom or it could be a list where all of the items cannot
list views with dynamic content size and is optimized to calculate cell heights be displayed on the screen at the same time. UIScrollView is a superclass
in a background thread, which makes it super performant. of UITableView, UICollectionView, and UITextView; therefore, all of
them get the same features as UIScrollView.
When you work with UIScrollView, you define yourself as its delegate by
7.14 How do you work with UICollectionView? adopting the UIScrollViewDelegate protocol. There are a lot of meth-
ods that you get with that delegate but the main one you usually work with
This is the same questions as the one about UITableView. Your interviewer is is scrollViewDidScroll(UIScrollView). In this method, you can do
trying to figure out if you’ve worked with more complex UIs for lists of items. additional work when the user scrolls table view content, for example.
101 102
7.16 What is UIStackView? When would you use Red flag: You probably shouldn’t say that you’ve never heard of other ap-
proaches. It’s fine if you never had a chance to try them out in real apps,
it and why? though.
103 104
do all the heavy lifting of setting it up, instantiating the UI, filling it with data,
and so on.
There’s a very promising alternative though - LayoutTest-iOS.
LayoutTest-iOS helps you test your UI and automates a lot of tedious setup,
AutoLayout constraint checks, data variations, and other things.
Red flag: Saying that you don’t test your UI is not a red flag per se but you
should at least acknowledge that if you don’t do it, you should be doing it.
7.20 Conclusion
UI questions are very common on iOS interviews because virtually more than
half the time spent building iOS apps will be views-related work. For some
apps it is crucial to build a sleek and nice UI; others can go by with just bare
bones. As usual, things you should keep in mind are reusability and the single
responsibility principle. If your UI is not tightly coupled to other parts of your
app then it’s going to be very easy to update it if it’s not perfect or if specs have
changed.
105 106
Interview questions covered in this chapter:
• What is MVC?
Chapter 8 • What is MVVM?
• What are the SOLID principles? Can you give an example of each in
Design Pattens, Architecture, iOS/Swift?
• What are the design patterns besides common Cocoa patterns that you
know of?
Understanding design patterns and architecture is what distinguishes great de-
velopers from just good ones. They are the hardest concepts to grasp, but they
give you the best return if you take time to study and practice them. 8.1 What design patterns are commonly used in
Design patterns give you a common language to use to talk about concepts in iOS apps?
your code with other developers. They improve the readability and testability
of your code. This question is a common one on interviews for positions of all levels, maybe
Architecture helps you build maintainable software that is easy to change be- with the exception of junior positions. Essentially the idea is that in working
cause the only thing constant in software development is that software is going with the iOS platform, you as a developer should be familiar with commonly
to change. used techniques, architecture, and design patterns used on iOS.
In this chapter we’ll cover questions about general programming, and iOS Expected Answer: Typical commonly used patterns when building iOS ap-
specifically, architecture and design patterns. The topics will vary from good plications are those that Apple advocates for in their Cocoa, Cocoa Touch,
old MVC, Delegate, Singleton, and so on, to SOLID and FRP. Objective-C, and Swift documentation. These are the patterns that every iOS
developer learns. They include MVC, Singleton, Delegate, and Observer.
107 108
8.1.1 MVC Cocoa already - Delegate, one-to-one observation, and KVO (key-value ob-
serving), one-to-many observation.
The good old Model-View-Controller is Apple’s go-to application architecture Red Flag: When interviewer asks this question (in one form or another) what
design pattern. It’s good for small/simple apps, but not sustainable in the long they are looking for is something besides MVC. Because MVC is the go-to
run. We’ll cover it in more details in the following section. 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.1.2 Singleton
This is a common OOP design pattern where you create the one and only in-
stance of a class that will be used everywhere in the application where an in-
8.2 What is MVC?
stance of that class is necessary. This is a useful design pattern but commonly
overused to the point of becoming an anti-pattern. The main issue is that de- MVC is Apple’s design pattern of choice and a question about it is unavoidable
velopers often use singletons to store a global state which is never a good idea at any iOS interview. When you are asked this question, it is a great opportunity
due to race conditions and other types of data overrides that inevitably happen. to spin it into a deeper conversation about software architecture and design. If
you’re applying for a mid- or senior-level position, talk in length about MVC
and its advantages, disadvantages, and alternatives.
8.1.3 Delegate Expected Answer: MVC stands for Model-View-Controller and is Apple’s
go-to design pattern for iOS applications. Models represent data, Views rep-
Delegate is one of the core Cocoa design patterns. It is a variation of the Ob- resent the UI, and Controller, the business logic. That more or less maps into
server pattern where only one object can observe or be delegated to events
from another object. It’s a one-to-one relationship that is implemented through
• Models being your NSObject subclasses or Core Data objects that rep-
protocols. Cocoa itself uses this pattern a lot with UITableViewDelegate,
resent your data;
UITableViewDataSource, UIPickerViewDelegate, and similar proto-
cols that are exposed by the framework for developers to use. (We also dis- • Views being your UIView subclasses and UIViewControllers that draw
cussed Delegate in the fundamentals chapter.) things on the screen;
• Controller being your application’s logic and classes responsible for
8.1.4 Observer that.
This pattern is a common one in iOS. It’s a design pattern that helps objects ob- Pay attention to where UIViewController is. It is in the View layer. The reason
serve state changes or events in other objects without coupling that observation being that at the end of the day, it does (or should do) what it name entails -
to internal implementation of those objects. Developers can always implement control the view, no more, no less. Too often though, and Apple’s code ex-
the Observer pattern themselves, but there are two built-in implementations in amples are guilty of that too, developers put all the business logic into view
109 110
controllers and it quickly grows out of proportion and the whole MVC archi- We’ll talk about both of those later in this chapter.
tecture becomes a Massive-View-Controller instead.
Red Flag: If you’re applying for anything beyond a junior position, it is un-
Advantages acceptable to talk about MVC as a design pattern that is the best out there
because Apple picked it. Apple is good at what they do - building hardware
Some architecture is better than no architecture and I can understand why Ap-
and frameworks. And their goal with their documentation and sample code is
ple chose MVC as its main base design pattern of choice - it’s simple to under-
to get beginner developers up to speed as soon as possible. What they are not
stand! Even novice developers can quickly wrap their heads around it and get
good at is building apps. They never had a case for a complex and big enough
going, cranking up a bunch of views, models, and view controllers. Where it
application, so following their advice with regard to architecture is wise only
falls short though is more complicated cases.
in the beginning and only to a degree. If you’re working on a serious enough
Disadvantages application with locally stored data and an HTTP connection, you have to use
The main disadvantage of MVC is its simplicity, which pretty quickly starts to something better than MVC. As mentioned before, MVVM is a low-hanging
limit you. As I’ve mentioned previously, a lot of developers tend to abuse view fruit, but you could and should go farther and apply SRP and other design and
controllers and give them too much responsibility. The remedy for that is more architecture best practices to your code.
explicit layer boundaries and the Single Responsibility Principle in general that
we’ll talk about later in this chapter.
MVC quickly falls short in edge cases. For example, where do you put a service 8.3 What is MVVM?
object that does HTTP networking? It’s certainly not a view. Is it a model?
Nope. Is it a controller? Hmm. . . not really a controller either. . . MVC is a fine pattern for the simplest apps. When you build something more
Alternatives complex you need a better architectural and design approach for your codebase
than that. One of the alternatives that is embraced by the iOS community is
There are several things that can be done about MVC’s shortcomings but the
MVVM. This question inevitably will arise through conversations about archi-
main two solutions are
tecture and design. Answering it well will make you stand out from the crowd
because, to my knowledge, not that many developers actually use this very
• MVVM (Model-View-View-Model) design pattern useful design pattern.
• SRP (Single Responsibility Principle) Expected Answer: MVVM stands for Model-View-View-Model. This design
pattern is effectively a subset and extension of MVC. With MVVM on iOS,
MVVM helps with slimming down the notorious Massive-View-Controller by in addition to models, views, and controllers, we’d also have view models that
extracting the business logic and the data out from view controllers into view play an important role in data presentation and delegating business logic trig-
models (and ultimately other objects). SRP helps with setting firm boundaries gered by the view layer (views and view controllers). It fits nicely into existing
for your code for object responsibilities. Each of them does only one thing and MVC architectures and extends it by making it more testable and less coupled.
will change only for one reason. That greatly reduces the complexity of your To illustrate where and how we use view models, consider this example:
code and makes it more composable, maintainable, and receptive to change.
111 112
As you can see there’s typical MVC stuff going on here. We have a view con-
import UIKit
troller that upon initialization takes in some state to be displayed in its button
class MyViewController: UIViewController { title when the view is loaded. And it also prints that title when the user clicks
private var someButton: UIButton! on that button.
private var buttonTitle: String! Seems ok, doesn’t it? Well, there’s a responsibility and coupling problem here
convenience init(buttonTitle: String) { that quite often leads to a “Massive View Controller” issue. The problem is
self.init() that our view controller is a view layer object that is responsible for displaying
self.buttonTitle = buttonTitle a UI, but it currently also tries to get into the business of managing state and
} executing business logic. The way it does it is by keeping a reference to state,
override func viewDidLoad() { in our case the buttonTitle string that is passed to it upon initialization, and
super.viewDidLoad()
by having the business logic in the buttonClick method.
self.someButton = self.setupButton(title: self.buttonTitle)
} A way to improve is to introduce a viewmodel object for business logic and
state and inject it as a dependency in our view controller:
private func setupButton(title: String) -> UIButton {
let button = UIButton()
button.setTitle(title, for: .normal) import UIKit
button.addTarget(self,
action: Selector(("buttonClick:")), class MyViewModel {
for: .touchUpInside)
return button let title: String
}
init(title: String) {
public func buttonClick(sender: AnyObject) { self.title = title
// let's assume there's some business logic happening here }
print("there's an action here that
\ relies on the state of your application") func printAction() {
print("such as button title - for example, \(self.buttonTitle!)") print("executing business logic")
} print("printing button title: \(self.title)")
} }
}
// creating a new instance of our VC
let myVC = MyViewController(buttonTitle: "some button title") class MyViewController: UIViewController {
// simulating our VC's appearance on the screen
myVC.view private var viewModel: MyViewModel!
// simulating the user clicking our button private var someButton: UIButton!
myVC.buttonClick(sender: NSObject())
convenience init(viewModel: MyViewModel) {
self.init()
// output:
// there's an action here that relies on the state of your application self.viewModel = viewModel
// such as button title - for example, some button title }
113 114
super.viewDidLoad() view controller simply becomes an input device, just like terminal or voice is.
self.someButton = self.setupButton(title: self.viewModel.title) You can also do the same thing with other UIView subclasses - not only view
}
controllers and create view models for them when they grow out of proportion
private func setupButton(title: String) -> UIButton { and carry too much state and logic.
let button = UIButton()
button.setTitle(title, for: .normal) This in a nutshell is what the MVVM pattern is and what it helps with in your
button.addTarget(self,
action: Selector(("buttonClick:")), code. For me personally it’s been an invaluable tool for refactoring and code
for: .touchUpInside) improvement that I’ve used when joining projects. Slimming down view con-
return button
} trollers is typically the lowest-hanging fruit for improvement on iOS projects.
public func buttonClick(sender: AnyObject) { Red Flag: MVVM is not a silver bullet, but it becomes a more and more
// trigger business logic here
self.viewModel.printAction() widespread tool for refactoring and decoupling on iOS projects. If you’re aim-
} ing for something higher than a junior position, you need to at least be aware
}
of it and have some experience using the pattern and recognizing when it could
// creating an instance of MyViewModel to keep track of state be of use to you.
// and to execute business logic
let myViewModel = MyViewModel(title: "some button title")
115 116
interface. This layer includes UIWindows, UIViews, AutoLayout, UIView- with data management and persistence. Stuff in the storage layer is supposed
Controllers, table views, collection views, CALayers, animations, touch to be the ultimate source of truth for your application. You should be able to
events, app delegate, and other things with which the user interacts with your rely on it and definitely say if you have something or not; other things and data
app. from other layers are more temporary and ephemeral.
The main purpose of this layer of responsibility is to display UI elements on the
screen and to take user input in and delegate it to the rest of your application.
The key here is not to put too much code that is responsible for storage or
service or business logic in the UI layer because it could cause overblown view
controllers and views issues, which is never good for any codebase.
8.4.4 Business Logic Layer:
Into the business logic layer go objects that are responsible for the application’s
8.4.2 Service Layer: business logic - objects that use components and objects from other layers to
achieve results and the work for the user. Coordinators that use service objects
The service layer is responsible for all external communication your applica- in conjunction with storages to orchestrate data receiving from backend APIs
tion has. HTTP API client objects and classes, Bluetooth Low Energy (BLE) and persistence to Core Data would be one example. Another could be a man-
code, analytics services, third-party (non-UI-related) services, location ser- ager that takes care of token encryption and saving to Keychain using Keychain
vices, GPS/gyroscope, and the respective data mappings from JSON and other storage and some kind of encryption service. The main idea is that this layer
formats to your domain objects would all constitute this layer. helps us keep services, storages, and other layers decoupled from each other
and tells them what to do to achieve results. This layer is where the actual
The key thing here, as with every other layer, is not to mix up responsibili- interesting stuff that your application does happens.
ties from other layers. For example, never put UI code inside of your service
objects. Alert pop-ups and UI updates have no business being in HTTP net- Virtually every iOS app has the previously described layers of responsibility.
working code, it’s the UI layer’s responsibility to handle that. Same goes for Even an app that does everything locally and never connects to an HTTP API
storage - don’t save things to disk or the database in your networking code. It would have to eventually track user behavior and would do so using a track-
doesn’t make any sense. ing/analytics service for that, which is the service layer. It definitely has some
data to store, even in its in-memory arrays, so it has a storage layer. It has some
views and view controllers to display, aka the UI layer. And of course, to be
8.4.3 Storage Layer: of any use to the user, it needs to coordinate all of those things, so here’s your
business logic layer.
The storage layer is responsible for storing things. That layer contains your Red Flag: Simply answering that every iOS app has a view, model, and con-
custom domain model classes and complex things such as Core Data, Realm, troller as layers doesn’t cut it. Every iOS app is way more than that, and MVC
SQL, and NSFileManager. And it also has simpler storage solutions such as doesn’t cover a lot of edge cases when a class doesn’t strictly belong to either
NSUserDefaults, Keychain, and even in-memory arrays, sets, and dictionaries. a model, view, or controller. This is why you need to look at your code’s layers
The idea for that layer is to abstract out and decouple everything that has to do of responsibility more broadly.
117 118
8.5 What are SOLID principles? Can you give an return a different type of JSON.
example of each in iOS/Swift? This principle is the basis of the architecture and approach described in the
previous answer that I use myself when building any kind of application. Con-
sider this: all of those things around Post described previously are related to
Interviewers could ask this question on senior or architect position interviews.
the same layer of responsibility of your application - the storage layer. The
SOLID principles are relatively old but incredibly useful concepts to apply to
reason why they are grouped into that layer is because they are responsible for
any OOP codebase in any language. Watch a few of Uncle Bob’s talks on the
storing things and because the only reason for them to change is when you need
topic to fully appreciate the history behind them.
to change how you store things, not when you need to change your networking
On YouTube Bob Martin SOLID Principles of Object Oriented and Agile De- code, for example.
sign
Expected Answer: SOLID stands for Single Responsibility Principle, Open/Closed
Principle, Liskov Substitution Principle, Interface Segregation Principle, and 8.5.2 Open/Closed Principle
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
The Open/Closed Principle (OCP) states that your modules should be open
code. Let’s go through each of them.
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
8.5.1 Single Responsibility Principle you should be able to extend the behavior of your objects through inheritance,
polymorphism, and composition by implementing them using interfaces, ab-
The Single Responsibility Principle (SRP) is the most important one of them. stractions, and dependency injection. If, let’s say, you have a PostsStorage
It states that every module should have only one responsibility and reason to class that has a certain interface that allows you to store Post models in the
change. SRP starts with small concrete and specific cases such as a class and/or database. According to that principle, when you want to extend and add be-
an object having only one purpose and being used only for one thing. The idea havior and features to your PostsStorage, you should be able to do that
is that when, for example, you create a new model class called Post, its sin- through inheritance and through injecting new dependencies into that storage.
gle purpose and responsibility is to hold the data and information about a post. For example, if you want to change the database that the storage saves posts
It’s a model class, it should do no more, no less. It should not be accessing to from Core Data to Realm you have two options: either you subclass from it
the database to save itself. It should not be creating underlying comments or and override methods that call Core Data and use Realm there instead or you
changing them in any way. It should not be parsing JSON to create a new inject a different database adapter/accessor dependency that complies to the
post out it. All of those things are single responsibilities of other objects that same protocol as the Core Data one but uses Realm under the hood instead. In
should not be mixed into that Post class. The Post class has only one reason both scenarios though, every object that was previously using PostsStorage
to change - it changes when we need to change the data structure of our posts should still be able to use it as before without any changes because in both sce-
in our application. It should not change because we decided to swap the un- narios, the PostsStorage’s interface that they relied on hasn’t changed. We
derlying database to Realm from Core Data or because our backend decided to effectively extended PostsStorage behavior without modifying it. It nicely
119 120
aligns with SRP because PostsStorage hasn’t had a reason to change when
protocol WorkerInterface {
we swapped the underlying database to Realm; it was not PostsStorage’s func eat()
responsibility to work with it in the first place. func work()
}
be replaceable with instances of their subtypes without altering the correctness func work() {
print("worker's working")
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 re- }
placeable and injectable wherever that interface or class that you subclassed class Contractor: WorkerInterface {
from was used. This principle is often referred to as design by contract or, as func eat() {
print("contractor's eating lunch")
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
func work() {
that your interfaces that you subclass from promise to fulfill and that by sub- print("contractor's working")
classing, those subclasses could be used anywhere where the superclass was }
}
previously used. If we look at our PostsStorage as an example again, then
according to Liskov’s Substitution Principle we could say that if we subclass class Manager {
from it, let’s call it BetterPostsStorage, then everywhere we were using
private let workers: [WorkerInterface]
the original PostsStorage, we could be using BetterPostsStorage in-
stead and our app won’t break or misbehave in any way. init(workers: [WorkerInterface]) {
self.workers = workers
}
func manage() {
8.5.4 Interface Segregation Principle workers.forEach { (worker: WorkerInterface) in
worker.work()
}
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 let worker1 = Worker()
let worker2 = Worker()
means is that when you create interfaces (protocols) that your classes imple- let contractor = Contractor()
ment, you should strive for and depend on abstraction over specificity but not
let manager = Manager(workers: [worker1, worker2, contractor])
until it becomes a waste where you have to implement a bunch of methods
your new class doesn’t even use. For a lack of a better (shorter) example, let’s manager.manage()
121 122
Here we have a WorkerInterface that has two methods eat() and work(). print("robot's working")
And we have two classes that implement it: Worker and Contractor. And }
}
we have a Manager that relies on WorkerInterface to call work() on each
one of the passed worker and contractor objects to initiate the work. It’s all nice
class Manager {
and good and we are assuming here that all workers and contractors are humans
private let workers: [WorkerInterface]
who can work but also need to eat so implementing the eat() method in both
of them is perfectly reasonable (we are assuming that the eat() method is init(workers: [WorkerInterface]) {
self.workers = workers
called on those objects somewhere else in the application). }
But this quickly becomes unreasonable when we introduce a Robot class that func manage() {
complies to the same WorkerInterface: workers.forEach { (worker: WorkerInterface) in
worker.work()
}
}
protocol WorkerInterface { }
func eat()
let worker1 = Worker()
func work() let worker2 = Worker()
} let contractor = Contractor()
let robot = Robot()
class Worker: WorkerInterface {
let manager = Manager(workers: [worker1, worker2, contractor, robot])
func eat() {
print("worker's eating lunch") manager.manage()
}
func work() {
print("worker's working")
}
This violates ISP because our Robots don’t need to eat and Robot is forced to
} implement an interface it doesn’t fully need, hence an empty eat() method.
class Contractor: WorkerInterface { What we need instead is to extract better, more concrete interfaces and use
func eat() { them instead:
print("contractor's eating lunch")
}
protocol WorkableInterface {
func work() { func work()
print("contractor's working") }
}
} protocol FeedableInterface {
func eat()
class Robot: WorkerInterface { }
// do nothing here. cuz robots don't eat. class Worker: WorkableInterface, FeedableInterface {
func eat() {}
func eat() {
func work() { print("worker's eating lunch")
123 124
} Now we rely on a more specific WorkableInterface that Manager uses,
and Robot doesn’t have to implement what it doesn’t need. This in a nutshell
func work() {
print("worker's working") is what the Interface Segregation Principle is all about. You have to either
}
} do a little bit more design up front to get your interfaces/protocols right or
you resolve it with adapters in existing systems. But ISP helps you maintain
class Contractor: WorkableInterface, FeedableInterface {
Liskov’s Substitution Principle in your code as well.
func eat() {
print("contractor's eating lunch") This principle ties back into the current trend of protocol-oriented program-
} ming.
func work() {
print("contractor's working")
}
} 8.5.5 Dependency Inversion Principle
class Robot: WorkableInterface {
The Dependency Inversion Principle (DIP) states, depend on abstractions, not
func work() {
print("robot's working") 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 it’s
initialization or configuration rather than let the object create or fetch/find its
class Manager {
dependencies for itself. Let’s look at the following example where DI is not
private let workers: [WorkableInterface]
applied:
init(workers: [WorkableInterface]) {
self.workers = workers
} class MyAPIClient {
func manage() { func httpGet(url: String, success: () -> Void, failure: () -> Void) {
workers.forEach { (worker: WorkableInterface) in // let's assume we do some http networking stuff here
worker.work()
} // and let's pretend it succeeds
}
} success()
}
let worker1 = Worker() }
let worker2 = Worker()
let contractor = Contractor() class PostsService {
let robot = Robot()
lazy var apiClient: MyAPIClient = { [unowned self] in
let manager = Manager(workers: [worker1, worker2, contractor, robot]) return MyAPIClient()
}()
manager.manage()
func fetchPostsFromServer(success: () -> Void, failure: () -> Void) {
// more business logic to prepare url and params here
125 126
let postsUrl = "some_endpoint_url" func httpGet(url: String, success: () -> Void, failure: () -> Void) {
// let's assume we do some http networking stuff here
apiClient.httpGet(url: postsUrl, success: {
success() // and let's pretend it succeeds
}, failure: {
failure() success()
}) }
} }
}
class PostsService {
Here when posts service creates its own instance of api client internally when let postsUrl = "some_endpoint_url"
it needs it and then stores it in a property for future use. Overall it’s not apiClient.httpGet(url: postsUrl, success: {
that bad because here we at least separate some responsibilities and delegate success()
}, failure: {
low level networking code implementation to api client instead of keeping it failure()
})
posts service. But the problem with this is that PostsService is tightly cou- }
pled to MyAPIClient; whenever MyAPIClient’s public interface changes, }
PostsService will have to change as well. This violates the Dependency let myApiClient = MyAPIClient()
Inversion Principle because our high-level module (i.e., PostsService) de-
let postsService = PostsService(apiClient: myApiClient)
pends on the low-level module MyAPIClient. Instead, both should depend on
abstractions. The Dependency Injection technique can help us with that. postsService.fetchPostsFromServer(success: {
print("change some UI upon successful fetch of posts here")
}, failure: {
With the Dependency Injection technique, instead of creating an instance of print("show some alert with an error")
MyAPIClient internally in PostsService, we would inject in posts a service })
object upon its initialization. Also we’d refactor the PostsService class in a
way that it does not depend on a specific and concrete MyAPIClient class but
As you can see PostsService now depends on an abstraction, Abstract-
instead relies on an interface abstraction:
APIClient, and gets its apiClient object injected upon initialization. The
great thing about that is that now we can easily create a new type of API client
protocol AbstractAPIClient {
func httpGet(url: String, success: () -> Void, failure: () -> Void) (let’s say one with better password security or something) and we’d simply
} inject instances of that into PostsService as long as that new API client
class MyAPIClient: AbstractAPIClient { conforms to AbstractAPIClient that PostsService depends on. Posts
service doesn’t have to change when that happens.
127 128
By applying the Dependency Injection technique we’ve not only complied with this case is to install library B version 2.1.0 because it will satisfy both
the Dependency Inversion Principle (DIP) but we also achieved better decou- A and C. But the problem is that you have already added library B version
pling between our objects, complied with the Single Responsibility Princi- 2.2.0 to your project. Now you’ll have to remove it and remove all the code
ple (SRP), achieved the Liskov’s Substitution Principle (LSP), and made our that uses APIs that are only in 2.2.0 and not in 2.1.0. And then you’ll
PostsService open for extension / closed for modification (OCP). have to rewrite your code so that it uses APIs of library B version 2.1.0.
This is a lot of manual work that you as a developer should not be handling
SOLID principles are the bedrock of good OOP design. Applying these prin-
because this example is simplified and the real-life issues related to dependency
ciples will help you build better, more maintainable software.
management version conflicts are way more severe.
The solution to those types of issues is a dependency management tool, and the
most popular one in the iOS community is Cocoapods. Cocoapods is a Ruby
8.6 How do you manage dependencies in iOS ap- gem that helps you manage all the dependency’s complexity, resolves version
plications? numbers of libraries (and their dependencies) that your project depends on, and
just in general makes your life easier when setting up iOS projects. The way
This is not necessarily an architecture or design patterns question but it is never- it works - it first figures out what libraries (called pods) our project depends
theless related and important. By dependencies they mean the code you don’t on by reading a list in your project’s Podfile. Then it will download those
write yourself but use to build your application, that is, third-party libraries libraries from their respective github repositories and put them together in an
and frameworks. Your interviewer will gauge your level of experience setting Xcode project called Pods. After that it will create a new Xcode workspace for
projects up and managing dependencies on big and small projects by asking your project and that new Pods project and will put them both in. It will also
this question. set all the project settings and workspace settings up the way that your code is
fully ready to import the libraries and start using them.
Expected Answer: Dependencies management is something you quite often
don’t think about right from the beginning of the project, usually not until you If you need help setting up your project, have a look at this video where I walk
get to the point when you need to use a third-party library or a framework. Then you through a typical Cocoapods setup: iOS Project Setup with Cocoapods
a question presents itself - how do you do that? A naive approach would be to There’s an alternative to Cocoapods called Carthage. Carthage uses a different
copy third-party code that your app depends on and just drag-and-drop or copy approach to dependency management where it creates framework binaries for
it into your project. The problem with that solution is that third-party libraries your dependencies but leaves it up to you to integrate them into your project.
themselves have their own dependencies and sometimes dependencies from It’s an alternative that’s more flexible than Cocoapods but is harder to use.
different libraries conflict with each other. For example a common scenario
Another error prone way of handling dependencies is to use git submodules but
is the following: you import library A version 1.1.0 and it depends on
you’ll have to do all the configurations and imports yourself.
library B versions from 2.1.0 to 2.2.0. To satisfy the requirements
of library A you add library B version 2.2.0 (the latest) to your project. Red Flag: The biggest red flag would be to say that you’re copying or dragging
Then later you add library C version 0.5.0 to your project. But library and dropping external libraries/code manually into your codebase. This is an
C depends on library B version 2.1.0. So now you have to resolve the unmaintainable solution that will not work in the long and short run.
version conflict between library A and C depending on B. The resolution in
129 130
8.7 What is Functional Programming and Func- them highly composable.
tional Reactive Programming? Swift doesn’t have a native support for FRP but there are two excellent libraries
out there that implement functional reactive programming concepts and make
them easily available to us. Those libraries are ReactiveCocoa and RxSwift.
Functional programming (FP) is the new hotness in iOS/Swift, JavaScript, and ReactiveCocoa offers composable, declarative, and flexible primitives that are
other dev communities. Except that it’s actually not that new. Expect this built around the grand concept of streams of values over time. These primitives
question either in regards to Swift features or as a bigger architectural and can be used to uniformly represent common Cocoa and generic programming
conceptual discussion question. patterns that are fundamentally an act of observation. ReactiveCocoa is a great
Expected Answer: Functional programming (FP) is a style of programming way of getting FRP in your codebase, and Ash Furrow has written an entire
that puts emphasis on functions as the main computational unit and treats them book on the subject of FRP where he uses ReactiveCocoa. The book’s called
like first-class citizens in your code. Those functions are akin to mathematical Functional Reactive Programming on iOS.
functions. The functional programming paradigm avoids mutability and state RxSwift is an implementation of Reactive Extensions (Rx) in Swift. Reac-
change either completely or as much as possible. FP is a declarative style of tive Extensions is a library for composing asynchronous and event-based pro-
programming where you would declare what your code should do instead of grams using observable sequences. RxSwift is a great (and in my opinion the
telling it explicitly (i.e., imperatively) how to do it (what steps to take, etc.) best) implementation of functional reactive programming concepts in Swift and
like in imperative programming. In contrast, imperative programming is a set many other languages. The advantage of learning that library is that knowl-
of steps to execute that usually heavily relies on state and mutability to do so. edge is transferable and can be applied to any other platform/language where
Swift introduces more FP concepts built into the language than Objective-C: Reactive Extensions is available (currently they have implementations in Java,
value types, functions as first-class citizens, higher-order functions, and so on. JavaScript, C#, C#(Unity), Scala, Clojure, C++, Lua, Ruby, Python, Groovy,
Those concepts make Swift functional friendly but not a fully functional lan- JRuby, Kotlin, Swift, PHP, Elixir, etc.).
guage. Red Flag: These days the expectation is that developers at least understand
Functional Reactive Programming (FRP) is a declarative programming paradigm some basic concepts of FP. You don’t have to know what FRP is but you need
that combines in itself functional programming and reactive (async dataflow to be able to explain how FP differs from the typical imperative style of pro-
programming) paradigms. It is also a declarative style of programming where gramming.
you would declare what your code does rather then explicitly state how it does
it. The reactive component of FRP allows us to introduce and describe the con-
cept of time, which is hard to work with in pure functional programming. FRP
helps us deal with user input and the asynchronous nature of iOS applications
8.8 What are the design patterns besides common
in general (user input happens at some point in time, networking will finish Cocoa patterns that you know of?
some time in the future, etc.).
FP and FRP rely heavily on higher-order functions such as map, reduce, and This is an advanced question that an interviewer will ask when you interview
filter that take functions as arguments and return other functions which makes for a senior or architect position. Be ready to recall a bunch of Gang of Four
131 132
patterns and similar. This could be a followup to "What design patterns are }
commonly used in iOS apps?" question.
class TrainingAndPreparationCenter {
func workerableUnit(_ workerType: WorkerType) -> WorkableInterface {
Expected Answer: Besides commonly used MVC, Singleton, Delegate, and switch workerType {
Observer patterns there are many other that are perfectly applicable in iOS ap- case .Contractor:
return Contractor()
plications: Factory Method, Adapter, Decorator, Command, and Template. case .Robot:
return Robot()
default:
return Worker()
8.8.1 Factory Method }
}
}
Factory Method is used to replace class constructors, abstract and hide objects class Manager {
initialization so that the type can be determined at runtime, and to hide and con-
private let workers: [WorkableInterface]
tain switch/if statements that determine the type of object to be instantiated.
init(workers: [WorkableInterface]) {
Let’s expand our previous Workers/Contractors/Robots example to demonstrate self.workers = workers
it: }
func manage() {
workers.forEach { (worker: WorkableInterface) in
protocol WorkableInterface { worker.work()
func work() }
} }
}
class Worker: WorkableInterface {
let trainingAndPreparationCenter = TrainingAndPreparationCenter()
func work() {
print("worker's working") let worker1 = trainingAndPreparationCenter.workerableUnit(.Worker)
} let worker2 = trainingAndPreparationCenter.workerableUnit(.Worker)
} let contractor = trainingAndPreparationCenter.workerableUnit(.Contractor)
let robot = trainingAndPreparationCenter.workerableUnit(.Robot)
class Contractor: WorkableInterface {
let manager = Manager(workers: [worker1, worker2, contractor, robot])
func work() { manager.manage()
print("contractor's working")
}
}
As you can see we now have a TrainingAndPreparationCenter object
class Robot: WorkableInterface {
that creates instances of WorkableInterface and the concrete instance type
func work() { instantiated is determined at runtime. The idea is that the Factory Method helps
print("robot's working")
} you with SOLID principles by abstracting out how and what instances of con-
} crete type are created and lets you rely on the abstract interface instead. There
enum WorkerType { is another related design pattern called Abstract Factory that is also useful in
case Worker, Contractor, Robot iOS apps, but I rarely see it in the wild.
133 134
8.8.2 Adapter }
}
Adapter is a design pattern that helps you, as the name suggests, adapt the class UserShareableAdapter: Shareable {
interface of one object to the interface of another. This pattern is often used let user: User
when you try to adapt third-party code that you can’t change to your code, or
init(user: User) {
when you need to use something that has an inconvenient or incompatible API. self.user = user
Here’s an example: }
135 136
they will use those user and post objects’ data to satisfy Shareable and
let user = User(email: "some@email.com", username: "some_username") SocialSharingService API, therefore “adapting” user and post objects
let post = Post(title: "some post title", body: "post content") to its API.
let someUserInout = SomeUserInput(textContent: "this is some user text")
let userShareableAdapter = UserShareableAdapter(user: user)
So now if we ever want to share another model object, let’s say a Product,
let postShareableAdapter = PostShareableAdapter(post: post) then we don’t have to break its SRP and can just create another adapter that
let socialSharingService = SocialSharingService() will be supplying the right data from product to SocialSharingService
which preserves the SocialSharingService API and keeps it unchanged
socialSharingService.shareShareable(shareable: someUserInout)
socialSharingService.shareShareable(shareable: userShareableAdapter) regardless of new objects it needs to share. That way we not only implemented
socialSharingService.shareShareable(shareable: postShareableAdapter) the Adapter pattern but we also covered a lot of SOLID principles by doing it.
We have Shareable protocol. Those objects that conform to it can get us 8.8.3 Decorator
data necessary for sharing on social networks (think Facebook, Twitter, etc.).
We also have a SocialSharingService that takes objects that conform to Decorator is a wrapper around another class that enhance its capabilities. It
Shareable and knows how to send them up on network (or some other way) wraps around something that you want to decorate, implements its interface,
to share on social networks (side note: notice the name - service, i.e., external and delegates messages sent to it to the underlying object or enhances them or
communication). provides its own implementation.
We also have a SomeUserInput model object that directly conforms to Let’s take a look at the following example:
Shareable to be available for sharing by SocialSharingService. There
are also two other model objects that we’d like to share: User and Post. The protocol Product {
problem is that they don’t conform to the Shareable protocol, nor should func price() -> Int
func name() -> String
they. They could either be unavailable to us to change (think a third-party li- }
brary classes) or, in this particular case, it doesn’t make sense and breaks SRP
class FullPriceProduct: Product {
to have them implement Shareable. The reason it doesn’t make sense and
breaks SRP is that if we ever want to change the way we share things and the func price() -> Int {
return 1000
data we want to have for sharing, we’d have to modify those model classes. It is }
not their responsibility to change when we change sharing. Their single respon- func name() -> String {
sibility is to represent User- and Post-domain-specific data in our application. return "I'm a product"
}
No more, no less. }
The solution to that problem is adapters. In our case we introduce two adapters class DiscountedProductDecorator: Product {
UserShareableAdapter and PostShareableAdapter that themselves con-
private let decoratedProduct: Product
form to the Shareable protocol and take in and wrap respective User and
Post objects as parameters. Later, when SocialSharingService asks, init(decoratedProduct: Product) {
137 138
self.decoratedProduct = decoratedProduct protocol don’t have to know that they are working with a decorator that en-
} hances the original object. We have complied with multiple SOLID principles
func price() -> Int { again, especially the Open/Closed Principle.
return Int(Float(decoratedProduct.price()) * 0.75)
}
and adds (“decorates with”) additional behavior in the price() method to ap- class StorageSaveCommand: Command {
ply a discount to the resulting product price. At the end of the day you can
private let dataToSaveToDisk: String
wrap your objects in multiple decorators and use them just like the objects they
init(dataToSave: String) {
decorate because they comply to the same protocol. The users of the Product
139 140
self.dataToSaveToDisk = dataToSave 8.8.5 Template
}
func execute() { Template is a design pattern where the main concept is to have a base class
print("saving \(self.dataToSaveToDisk) to disk") that outlines the algorithm of what needs to be done. The base class has several
print("......")
print("done") 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
let productUrl = URL(string: "http://my-awesome-app.com/api/v1/products/12345")!
implementations of those steps are supplied by subclasses.
let getRequestCommand = HTTPGetRequestCommand(url: productUrl) The following example demonstrates template method pattern:
getRequestCommand.execute()
let jsonResult = getRequestCommand.result!
class Report {
let saveToStorageCommand = StorageSaveCommand(dataToSave: jsonResult)
saveToStorageCommand.execute() let title: String
let text: [String]
mands so powerful. If you have a more complicated command it could aggre- internal func outputHead() {
preconditionFailure("this method needs to
gate data it needs for execution over time and can even change the values it be overridden by concrete subclasses")
has stored in itself before the actual execution happens or a command could be }
never executed, for example. internal func outputBodyStart() {
preconditionFailure("this method needs to
To add undo/redo mechanics you’d utilize an array of Command objects and be overridden by concrete subclasses")
execute them as you push or pop from the list. Showing an example of that is }
another discussion for another chapter. If you want to learn more, please refer private func outputBody() {
to the resources at the end of this chapter. text.forEach { (line) in
141 142
outputLine(line: line) override func outputStart() {}
}
} override func outputHead() {
print("==========\(title)==========")
internal func outputLine(line: String) { print()
preconditionFailure("this method needs to }
be overridden by concrete subclasses")
} override func outputBodyStart() {}
143 144
Controller. Every time we subclass it, it provides “the algorithm imple-
mentation” and we override “hook methods” such as viewDidLoad(), view-
WillAppear(), and so on.
More about patterns:
For more details on Factory Method, Adapter, Decorator, Command, Tem-
plate, and many other design patterns’ implementations refer to the books Pro
Design Patterns in Swift and Pro Objective-C Design Patterns for iOS.
The patterns here are not the only ones you can use on iOS, but those are the
most common ones besides MVC and basics that I’ve seen in the wild.
Red Flag: Sticking only to MVC, Singleton, Delegate, and Observer patterns
is fine when you’re starting up 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.
8.9 Conclusion:
In this chapter we’ve covered design patterns and iOS apps architecture. These
are some of the most important things to know for iOS developers to get better
at their craft. By applying good architecture and design patterns, you help your-
self and your colleagues to have the common ground, language, and nomencla-
ture for things in code that you work with day to day. It improves the read-
ability, recognizability, maintainability, and flexibility of your code. It helps
you follow SOLID principles, which will help your code stand the test of time
and the most important and inevitable test that your codebase could ever face -
change!
145 146
Every app, big or small, needs to store data. Typically when iOS developers
think about storing data they think about Core Data or a similar database so-
lution. But the goal for us is to be practical and to know our options. It turns
out that Core Data is not always the best solution, and sometimes something
simpler might suffice.
Chapter 9
9.1 Storage Layer
Bonus Chapter: Storage A quick recap:
Evolution (AKA You Don’t The storage layer can be as simple as an array or a dictionary of data that
holds models in memory for your app. Or it can be as complex as a Core Data
Always Need Core Data!). or custom SQL ORM solution that can be observed and queried with advanced
predicates. The main purpose and responsibility of that layer is to store data
for your application and to play the role of the ultimate source of truth for the
rest of your code.
This chapter is a continuation of Chapter 6 Step Five: Learn How to Store Data.
In this chapter we’ll go over a refactoring process where we will evolve storage
classes that our application uses, starting with a simple in-memory array, to 9.2 Typical tools Used for Persistence in the Stor-
NSUserDefaults, to on-disk file storage, and then eventually to Core Data.
All along this process we will preserve the API of our storage unchanged, ad-
age Layer
hering to SOLID principles so that users of our objects and classes are not
concerned and coupled to our internal implementation. That way it will be The following classes, objects, and libraries/frameworks (in ascending order of
easy for us to change it, as you will see. complexity) are used in the storage layer:
The reason this chapter is called a bonus” chapter is because it is not techni-
cally focused on interviews and interview questions, but is instead about prac- • In-memory arrays, dictionaries, sets, and other data structures
tical day-to-day iOS development itself. This chapter is a sneak peek of my
next book that covers more practical stuff like what you see in this chapter. If • NSUserDefaults/Keychain
you’re interested in hearing about updates and progress on the next book please
sign up for the wait list here: • File/Disk storage
http://iosinterviewguide.com/next_book • Core Data
147 148
9.3 In-memory arrays, dictionaries, sets, and other Example:
data structures Let’s say your app is displaying posts that are fetched from the backend. A
typical storage class for Posts will look like this:
Probably when you hear the words “storage layer” you instantly think about
struct Post {
Core Data or a similar database technology that helps you persist things into let remoteId: NSNumber
tables. But surprisingly enough, your storage layer could be as simple as an in- let name: String
}
memory array where you store a list of things you’ve fetched from the backend
API, for example. The main thing is that you abstract that internal implemen- class PostsStorage {
tation out from the rest of your application. private var posts = Dictionary<NSNumber, Post>()
All Swift Collection Types and corresponding Objective-C types can be used as func savePost(newPost: Post) {
self.posts[newPost.remoteId] = newPost
the underlining mechanism for storage for your application. Array, NSArray, }
Set, NSSet, Dictionary, and NSDictionary could all be used to save
func getAllPosts() -> [Post] {
things in the storage layer. return Array(self.posts.keys.map { self.posts[$0]! })
}
Advantages:
func findPostByRemoteId(remoteId: NSNumber) -> Post? {
return self.posts[remoteId]
}
• easy and quick to create (they are just plain old arrays and hashes after }
all)
• quite often it is actually the only thing you need As you can see, there’s nothing crazy to it. It has an internal dictionary that
uses remoteId of Post structs as keys to store those objects.
• can use key-value observing (KVO) to be notified of changes The way you’d use that storage is pretty straightforward as well:
149 150
print(postsStorage.findPostByRemoteId(post2.remoteId))
9.4.1 NSUserDefaults
solution. Simply put, NSUserDefaults and Keychain are just key-value private let userDefaults = NSUserDefaults.standardUserDefaults()
storage that you can write primitive data to.
151 152
private let storageNameSpacePrefix = "my_posts_" Also, we slightly change our save and retrieve methods. Now they use
NSKeyedArchiver and NSKeyedUnarchiver to convert Post objects to
func savePost(newPost: Post) {
let newPostData = encodePost(newPost) NSData or decode them back from NSData to Post type before they can be
self.userDefaults.setObject(newPostData, written or read from NSUserDefaults.
forKey: self.postKey(newPost.remoteId))
}
Oh, and notice that we have to use storageNameSpacePrefix so that we get
func getAllPosts() -> [Post] { all the keys for our stored Posts later (otherwise
return Array(self.allPostKeys().map { (key) -> Post in
let postData = self.userDefaults.objectForKey(key) self.userDefaults.dictionaryRepresentation().keys will return
return decodeToPost(postData as! NSData) all they keys in NSUserDefaults).
})
} The important thing though is that our public API for the storage remains the
func findPostByRemoteId(remoteId: NSNumber) -> Post? { same. Everyone who was using it and relying on it will continue to do it the
if let postData = self.userDefaults.
\.objectForKey(self.postKey(remoteId)) as? NSData {
same way, but now the storage actually persists Posts in memory.
return decodeToPost(postData)
}
return nil let postsStorage = PostsStorage()
}
let post1 = Post(remoteId: 1, name: "Post 1")
private func encodePost(post: Post) -> NSData { let post2 = Post(remoteId: 2, name: "Post 2")
return NSKeyedArchiver.archivedDataWithRootObject(post) let post3 = Post(remoteId: 3, name: "Post 3")
} let post4 = Post(remoteId: 4, name: "Post 4")
• persists things to disk (so the data can be restored between app launches)
In this example, we replaced dictionary storage with NSUserDefaults. In or-
der for us to be able to save Post objects to NSUserDefaults, we have to im- • easy to use key/value storage
plement the NSCoding protocol on them. So we convert Post into a class and
implement init?(coder decoder: NSCoder) and encodeWithCoder
to code and decode individual Post objects. Disadvantages:
153 154
• can’t easily use KVO for notification (you’ll have to roll your own noti- and then reinstalls your app, you can check whether the flag is present or not
fication/observation system) and go with default onboarding flow for a new user, for example, and do some
other custom onboarding for returning users.
• can’t be used to store large amounts of data (it was not made for that)
• not that helpful when you need to filter and sort data
9.5 File/Disk Storage
9.4.2 Keychain File and disk storage are typically used to persist bigger chunks of data like
images and videos but they can also be used as a substitute for your database.
Keychain is the tool for storing data securely. This is where you’d store user File and disk storage are perfectly capable of storing the same type of objects as
passwords and tokens, not NSUserDefaults. NSUserDefaults: primitives like String and NSNumber, and dictionaries,
Typically, working with Keychain directly is a bit gnarly and tedious due to arrays, and custom objects that conform to the NSCoding protocol.
its C-based API. I recommend using a library wrapper like KeychainAccess or We will iterate over our previous storage example and swap the underlying
samkeychain instead. storage with an NSFileManager.
Advantages:
class Post: NSObject, NSCoding {
let remoteId: NSNumber
• key-value storage for primitive values let name: String
An interesting fact is that stuff saved in Keychain, unlike anything stored in func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(self.remoteId, forKey: "remoteId")
NSUserDefaults, will persist and survive an app uninstall/reinstall. The rea- coder.encodeObject(self.name, forKey: "name")
son being is that NSUserDefaults is the storage that is tightly coupled with }
}
your application and Keychain is a global secure system storage managed by
Apple. That is both an advantage and disadvantage that allows us to do nice class PostsStorage {
things like storing a flag on the first application launch in Keychain, indicat- private let fileManager = NSFileManager.defaultManager()
ing that the app was installed for the first time. Next time, if the user uninstalls
155 156
private let storageNameSpacePrefix = "my_posts_" return NSSearchPathForDirectoriesInDomains(.DocumentDirectory,
.UserDomainMask,
func savePost(newPost: Post) { true).first! + "/posts_storage"
let newPostData = encodePost(newPost) }
let key = postKey(newPost.remoteId)
saveDataToDisk(key, directoryPath: documentsDirectory(), private func saveDataToDisk(fileName: String,
data: newPostData) directoryPath: String,
} data: NSData) -> Bool
{
func getAllPosts() -> [Post] {
let filePath = "\(directoryPath)/\(fileName)"
return allPostKeys().map({ (fileName) -> Post in
let postData = self.fileManager. do {
\.contentsAtPath(fullPostPath(fileName))! try self.fileManager.createDirectoryAtPath(directoryPath,
return decodeToPost(postData) withIntermediateDirectories: true,
}) attributes: nil)
} let success = self.fileManager.createFileAtPath(filePath,
contents: data,
func findPostByRemoteId(remoteId: NSNumber) -> Post? { attributes: nil)
let postPath = fullPostPath(postKey(remoteId)) return success
if let postData = self.fileManager.contentsAtPath(postPath) {
return decodeToPost(postData) } catch {
} return false
return nil }
} }
private func postKey(remoteId: NSNumber) -> String { private func fullPostPath(postKey: String) -> String {
return "\(self.storageNameSpacePrefix)\(remoteId.stringValue)" return self.documentsDirectory() + "/" + postKey
} }
}
private func allPostKeys() -> [String] {
do {
let directory = self.documentsDirectory()
return try self.fileManager.contentsOfDirectoryAtPath(directory).
\.filter({ (path) -> Bool in
Here we still keep serializing our Post objects to NSData before we store
return path.containsString(self.storageNameSpacePrefix) them, but the underlying storing mechanics are now using a file manager that
})
} catch {
saves each post to disk as a file with a unique namespaced name.
return []
} The implementation is grown a little bit more with a few extra private methods
} and do/catch blocks to accommodate the NSFileManager API, but other
private func encodePost(post: Post) -> NSData { than that, it remains the same overall. We still use the remoteId of each
return NSKeyedArchiver.archivedDataWithRootObject(post)
}
post as a unique key to identify and access each post. To get all posts that
were stored in the getAllPosts() method, we examine the folder used by
private func decodeToPost(data: NSData) -> Post {
return NSKeyedUnarchiver.unarchiveObjectWithData(data) as! Post
the storage and get NSData for each file and decode it back to Post objects.
} When we store Posts in savePost() method, we encode them into NSData
private func documentsDirectory() -> String { and persist them to disk. And when retrieving individual Post objects from
memory in the findPostByRemoteId() method, we get NSData for that
157 158
unique remoteId and then decode it to thePost object. 9.6 Core Data
And the great thing is that, as with the previous iteration, our public API for
PostsStorage remains the same. Everyone who’s been using it will continue Finally, we’ve got the good old Core Data database storage solution. Core
to do so in the same fashion: Data is an object graph persistence framework that helps you save objects to
a database. Under the hood, it uses SQLite (with options to use in-memory
let postsStorage = PostsStorage() and binary stores), but the interface is completely abstracted out and we are
let post1 = Post(remoteId: 1, name: "Post 1")
interacting only with Core Data framework objects and classes when we use it.
let post2 = Post(remoteId: 2, name: "Post 2")
let post3 = Post(remoteId: 3, name: "Post 3")
let post4 = Post(remoteId: 4, name: "Post 4") NOTE: There are other database alternatives to Core Data such as Realm and SQLite.
We will not cover them in this edition, but you can learn more here
postsStorage.savePost(post1) https://realm.io and here https://github.com/ccgus/fmdb
postsStorage.savePost(post2)
postsStorage.savePost(post3)
postsStorage.savePost(post4)
There is a lot to Core Data and it is a fairly complex piece of technology but
print(postsStorage.getAllPosts()) overall you typically work with it using the following classes and objects:
print(postsStorage.findPostByRemoteId(post2.remoteId))
• can’t easily use KVO for notification (you’ll have to roll your own noti- • NSFetchedResultsController is a more functional reactive way of
fication/observation system) getting notifications about object changes in the database that are filtered
by criteria set in NSFetchRequest (think of it as notifications about
• not that helpful when you need to filter and sort data
database changes).
This storage mechanism is a step up from NSUserDefaults and is pretty • NSPredicate lets you add filters to NSFetchRequest queries.
robust when you need something more stable than just a key-value store but
you are not sure if you need a full-fledged database solution yet. • NSSortDescriptor lets you add sorting to your queries.
159 160
There are two major schools of thought when it comes to working with Core
struct Post {
Data: use NSManagedObject subclasses as your models or map and serial- let remoteId: NSNumber
let name: String
ize your custom model objects to NSManagedObjects and use them only for }
persisting data to the database.
class PostManagedObject: NSManagedObject {
@NSManaged var remoteId: NSNumber
@NSManaged var name: String
to persist data to disk. That way your code stays completely decoupled from let remoteIdAttributeDescriptor = NSAttributeDescription()
Core Data and model objects do not carry the burden of NSManagedObject’s remoteIdAttributeDescriptor.name = "remoteId"
remoteIdAttributeDescriptor.attributeType = .Integer64AttributeType
underlying behavior because they are not subclassing from them. There’s no remoteIdAttributeDescriptor.optional = false
remoteIdAttributeDescriptor.indexed = true
need to worry about multi-threading and NSManagedObjectContexts be-
cause most of your code operates with simple and straightforward let nameAttribute = NSAttributeDescription()
nameAttribute.name = "name"
NSObject/Object subclasses or structs. nameAttribute.attributeType = .StringAttributeType
nameAttribute.optional = false
Let’s look at an implementation of such approach:
161 162
nameAttribute.indexed = false if let postManagedObject = executeFetchRequest(fetchRequest)?.first {
return decodeToPost(postManagedObject)
postEntityDescriptior.properties = [remoteIdAttributeDescriptor, } else {
nameAttribute] return nil
}
let managedObjectModel = NSManagedObjectModel() }
managedObjectModel.entities = [postEntityDescriptior]
private func encodePost(post: Post) {
persistentStoreCoordinator = NSPersistentStoreCoordinator( PostManagedObject.postManagedObject(post.remoteId,
managedObjectModel: managedObjectModel) name: post.name,
do { context: managedObjectContext)
try persistentStoreCoordinator. }
\.addPersistentStoreWithType(NSInMemoryStoreType,
configuration: nil, private func decodeToPost(postManagedObject: PostManagedObject) -> Post {
URL: nil, return Post(remoteId: postManagedObject.remoteId,
options: nil) name: postManagedObject.name)
} }
catch {
print("error creating persistentStoreCoordinator: \(error)") private func saveDataToDatabase() -> Bool {
} if managedObjectContext.hasChanges {
do {
managedObjectContext = NSManagedObjectContext( try managedObjectContext.save()
concurrencyType: .MainQueueConcurrencyType) return true
managedObjectContext.persistentStoreCoordinator = } catch {
\ = persistentStoreCoordinator return false
} }
} else {
func savePost(newPost: Post) { return false
encodePost(newPost) }
saveDataToDatabase() }
}
private func baseFetchRequest() -> NSFetchRequest {
func getAllPosts() -> [Post] { let fetchRequest = NSFetchRequest(entityName:
\ NSStringFromClass(PostManagedObject))
let fetchRequest = baseFetchRequest()
let sort = NSSortDescriptor(key: "remoteId", ascending: true)
if let postManagedObjects = executeFetchRequest(fetchRequest) { fetchRequest.sortDescriptors = [sort]
return postManagedObjects.map({ (postManagedObject) -> Post in
return decodeToPost(postManagedObject) return fetchRequest
}) }
} else {
return [] private func executeFetchRequest(fetchRequest: NSFetchRequest)
} -> [PostManagedObject]?
} {
return (try? managedObjectContext.
func findPostByRemoteId(remoteId: NSNumber) -> Post? { \ .executeFetchRequest(fetchRequest)) as? [PostManagedObject]
}
let fetchRequest = baseFetchRequest() }
Here we are creating a struct Post that will be our actual model structure (that
163 164
is the thing that the rest of the application works with). And PostManaged-
postsStorage.savePost(post1)
Object, a subclass of NSManagedObject, is used to persist data mapped postsStorage.savePost(post2)
from Post objects to the database. PostManagedObject is only used inter- postsStorage.savePost(post3)
postsStorage.savePost(post4)
nally by PostsStorage to actually get data in and out from the database.
PostsStorage had experienced quite a change and now has NSPersistent- print(postsStorage.getAllPosts())
StoreCoordinator to set up the database and entities that are going to be print(postsStorage.findPostByRemoteId(post2.remoteId))
stored in it, and NSManagedObjectContext to help with data persistence
and fetching.
We are setting up our database in a PostsStorage initializer with
NSPersistentStoreCoordinator, NSEntityDescription, and
NSAttributeDescriptions (for remoteId and name properties). Nor-
mally this setup will happen somewhere else in the iOS application with the
help of Xcode’s Data Model files, and instead of NSInMemoryStoreType
we’ll have it use actual SQLite under the hood. But doing it explicitly in code 9.7 Storage Layer Plays Dual Role: Persistence
like this is a perfectly fine approach as well. and Data Mapping and Serialization
To fetch and save objects we use NSManagedObjectContext and NSFetch-
Requests. When the data is saved on the outside we work with a Post ob-
ject, but then we map it into a PostManagedObject that can be saved to As you saw with the previous examples, no matter how complex or simple those
Core Data and save it using managedObjectContext.save() in save- examples were, they all had the same public API in the storage, and the work
DataToDatabase() method. When we retrieve objects from the database, the storage has done internally has similar parallels across implementations.
we get back PostManagedObjects in the getAllPosts() and findPost- They all have some kind of permanent storage mechanism (in-memory dictio-
ByRemoteId() methods and then we map them back to Post objects that our nary, NSUserDefaults, Disk file storage, or Core Data database,
application can work with. etc.). And they all (except in-memory dictionary) encode or decode data before
But the bottom line, again, is that we have the same public API in the storage as saving or retrieving it.
before. Users of that storage can still rely on having savePost(), getAll- That is due to the nature of the storage layer itself. It has to map data to some
Posts(), and findPostByRemoteId() methods that save and find Posts kind of structure it can easily persist, and when retrieved back it is not useful
in and from the database: to the rest of the application. So it needs to be mapped back to model objects
and types that are convenient for us to work with.
let postsStorage = PostsStorage()
You have the option to implement data serialization/mapping yourself just like
let post1 = Post(remoteId: 1, name: "Post 1") we’ve done in the previous examples but there are plenty of libraries out there
let post2 = Post(remoteId: 2, name: "Post 2")
let post3 = Post(remoteId: 3, name: "Post 3") that can help you with that. Mantle and MTLManagedObjectAdapter are my
let post4 = Post(remoteId: 4, name: "Post 4")
go-to choices when working with Core Data and JSON, for example.
165 166
9.8 Switching Storage 9.10 Be Practical in Your Storage Layer Imple-
mentation and Decisions
As was mentioned in the beginning of this section, one of the biggest advan-
I’m a big believer in the using only what you need” philosophy. In the case
tages of abstracting out the storage layer is that you can swap underlying per-
of storage, that means don’t overthink what you really need to have from your
sistence mechanics when needed. Let’s say you start working on a new app
storage layer. When you get a handle on Core Data, it sounds great to use it
or a new feature and don’t know yet if you need persisted storage on a disk
everywhere for every application. This is not always the best approach. When
database. So instead you can start implementing your storage as a simple array
you have a hammer, everything looks like a nail.
or a dictionary and prototype or deliver your feature with that. And later when
you have more information and you know you really need to write the data to In my experience in-memory, NSUserDefaults, and file/disk storage
a database you can easily replace that under the hood array with a Core Data are useful for prototyping and for applications with small data footprints that
model and table. For the rest of your application nothing really changes - it can survive data wipes between app launches. Core Data, Realm, and SQL
accesses the data the same way as before because you had a clearly defined storage, on the other hand, give you an advantage of data observation and are
interface for that. very good database solutions when you need to store large amounts of data and
sort and filter them.
Keep your storage API clear and abstract out internal implementation following
the Single Responsibility Principle and you’ll be fine, no matter what storage
solution you’ve picked.
167 168
Chapter 10
Outro
Ok, so you’ve made it. You got to the end of this book.
I hope you learned something, or even a lot, along the way. And my best hope
is that you’ve gotten your dream job with the help of this book.
As I mentioned in the preface, I wrote this book because there wasn’t anything
like it out there, and when I was less experienced, I wished there was. The main
message of this book isn’t knowing all the questions and answering them “just
right” so you can pass that current pseudoexam called a technical interview.
The main message instead is you should know your shit, and then interviews
will be easy. The best approach I found to learning software development con-
cepts and languages, or anything you’re trying to learn, really, is to systematize
your learning. Get the big picture overview of what there is to learn about a
subject and then start to drill down into each branch of that tree. It’s as simple
as that.
Good luck!
169