My Journey in Developing an iOS App

Fadion Dashi
25 min readApr 25, 2017

A couple of months ago, I was thinking I hadn’t been giving iOS that much attention. For the past years, I’ve built some apps and done my share of experiments, but haven’t actually invested as much as I would have liked to. You know, in the midst of deadlines it’s not easy to get past the “it works” phase and move on to the next. Well, this time it was an experimental app and I had nothing pushing me, so I set a very slow pace. It was a fun experience which I’m eager to share.

The App

Keeping the motivation pump going on experimental apps isn’t that easy. So, what would be an app that I was going to work with, even when frustration hit? Pizza! Off course it’s pizza. Well, probably not that obvious, but it seemed interesting enough and had me think of a few challenges.

Pizzaiolo, as I named it, is a fairly simple app. It has 5 screens: home screen, pizza selector, pizza builder, shopping cart and payment. I settled for this basic functionality, as otherwise it would have taken too long, and if anyone’s interested in using it for their pizzeria, it can be extended in every possible way. Obviously, the app is open source so jump to the GitHub repository if you can’t wait to see some code.

The app in action

Isn’t the pizza builder neat? Took me a bit, but I believe it’s the highlight of the whole app. There’s something special in seeing virtual ingredients flying over a pie which you’ll not be consuming. If you missed it, check the above GIF again.

Now that you got the basic idea of what the app does, it’s time to move on to more interesting things. This is going to be a long journey, so why not grab something to eat while it’s still early. Pizza maybe?!

Design

What looks good but doesn’t have high quality, free to use photos? Pizza! I searched every website I know for “from the above” free photos of pizzas and I was disappointed, to say the least. May have found a handful and they weren’t that good either. That’s when I knew that I could spend my time better; design them myself.

9 custom designed pizzas

I ended up with 9 pizzas, mostly the classics like Margherita, Quattro Stagioni, Pepperoni, etc. It only took me a few hours and damn, it was fun. I would design pizzas all day for a good pay!

Now that I had finished procrastinating, I could focus on the UI of the app. Lately I’ve gone back and forth on MacOS (home) and Windows (work), so I’ve had to move between Sketch and Adobe XD too. The former is way more mature, so that’s what I’m using.

My design aimed at being minimalistic, as any lazy designer will tag their style. I’m using pages to organise artboards, symbols so I don’t recreate the same button 10 times, and text styles for some consistency. Nothing out of the ordinary. Download the files if you’re interested and modify them at will.

In the end, I got these to show off:

Sketch Artboards

Code

Depending on your background, this should be where the fun starts. And as you’re about to read on, it should get pretty comic, at least if RxSwift, MVVM and that stuff is amusing to you.

While developing iOS apps in the past, my main grievance have been network calls. Where do you put them? How do you save that data locally so the app is usable without internet connection? What strategy would be best to compare local and remote data, so that the UI is updated the least amount of times? Although I had found some way to keep sanity, it was far from perfect.

In researching for good answers to those questions, I found ReactiveX. It does much more than I ever wished, so I went head-on with it. ReactiveX is the first thing I’ll be covering.

ReactiveX (RxSwift)

Let’s conquer the final boss before moving on to the other, lesser ones. RxSwift is a beast that when tamed, has the capability to change your programming paradigm. Basically, it’s FRP (Functional Reactive Programming), a way of having observable streams of data that can be manipulated and combined using familiar functions like map(), reduce(), etc. If it’s over your head, trust me, I completely understand. I’ll try to simplify.

Essentially, what you can do with RxSwift is create observers and listen to them. If you’ve used any event system or something build on top of the Observer Pattern, than you should have a basic idea. Observers emit data once they have some, while subscribers wait and react on those data. Instead of the traditional way of having state variables or calling the same function every time something changes, with RxSwift it becomes much easier.

What makes RxSwift complicated is the vast amount of terms and features that overwhelm even the experienced ones. Subjects, variables, hot and cold, drivers and whatever. Once you know the basics, as in understanding how to create an observer and a subscriber, and do some simple manipulations, you’ll intuitively move up the stack.

A Basic Example

Let’s imagine we have a class that does some expensive calculations. We don’t want to run it on the main thread, hence blocking the UI, but also want to be notified when it finishes. Without RxSwift, most probably you’d go for a closure as a parameter to the function, which will be executed on the main thread once the calculation finishes. That’s a fine way of doing things, but what if you want to get that result multiple times? Either you’ll run the function multiple times, which makes no sense, or create some mechanism that caches the data, resulting in additional work. With RxSwift, it’s very simple.

The function returns an Observable that contains a String, does its work in a separate thread but returns it in the main one. Most of the code is RxSwift boilerplate, which is pretty standard when you have the basics down.

With an Observable in place, we need to listen to it, otherwise it’ll be a world of silence. We have the subscribe method for that:

The beauty in all of this is that you can have multiple subscribers to a single Observer and if using methods like shareReplay, you’ll be sure all of them get the same data while the process will be executed only once.

RxSwift isn’t only a bunch of functionality, but a paradigm that may change the way you code. Feel going completely reactive? Off course you can do that, but you can also mix and match where you see fit. The downside is that as a new paradigm, it’s more difficult to get your head around. Myself, I had to read on it for a few days to get the basics and then use it in Pizzaiolo to move somewhat beyond. Unfortunately, I don’t want to turn this article into a tutorial, as there are many good ones out there. The 3 part guide RxSwift for Dummies helped me a lot, so make sure to give it a look.

Solving the network problem

Remote and local data flow

Going back to why I researched RxSwift. For Pizzaiolo, as an experimental app, I could have settled for a network-only approach, where data is fed only by the API. However, waiting a couple of seconds for the data to come in every time you open the app is just terrible on the UX. I had to have some local storage.

Realm is great! It’s a high performant database that’s very simple to use. I’m saving the data that I get from the network to Realm, so next time it opens, the app loads in an instant. As a thin interface to Realm Models, I have ViewModels, respecting the MVVM architecture. I’ll talk in more details about both of them later on, so don’t worry if you aren’t familiar. As of now, just know that whenever I have a piece of data, remote or local, instead of transmitting it as a Realm model or a plain dictionary, I store it in a ViewModel.

The first thing I wanted to achieve is having a clean design on data managing. ViewControllers tend to fill up fast with all kind of stuff and I’ve been guilty of writing network code in there more than once. This time I created a hierarchy that could let me fetch data with the minimal amount of lines. It’s composed of:

  • A Network class, using Alamofire, that expects a URL and returns a Data object.
  • Mapper classes for each of my entities. For example, I have a PizzaMapper, CategoryMapper, and so on. These are responsible for transforming the Data object (which is a JSON actually) into models, persists them and return ViewModels.
  • Query classes for each entity. These are the only classes allowed to directly interact with realm and are used to fetch local data. Think of them as Repositories. As you might have guessed, they produce ViewModels too.
  • Manager classes for each entity. These are the orchestrators, as they combine Mappers and Queries in a, I’d go on and say, smart way.

What I’m interested in talking about are the Managers. The other classes are pretty straightforward and even the bits of RxSwift in there are not that different from the basic example I gave in the previous section. You can take a look in the repository just to get the idea.

This is where the magic happens:

While it may seem overwhelming to the uninitiated, it really is fairly simple, so let’s break down each step.

  • The network variable fetches the API for data and using flatMap (think of it as a pipe operator), it passes that data to the Mapper class, which in turn gives ViewModels. As I’m not subscribing but just calling the method, what I get in return is an Observable<PizzaViewModel> .
  • local gets too an Observable<PizzaViewModel> but locally from the Query class.
  • With data from both sources in hand, I need a way to combine them. The of operator is one of the ways to create an Observable, as is create or just. I’m telling it to create an Observable using both network and local.
  • Problem is, how should they be combined? What I need is to call them asynchronously, so local data doesn’t have to wait for the remote to finish. That’s when merge is useful. It combines both streams, but hands out each one’s data as soon as they are finished.
  • filter removes empty data. If the device isn’t connected to the internet, so it can’t fetch data, or local storage is empty, I don’t want to notify the subscribers. Errors (no connection, failed parsing, etc.) will propagate though.
  • distinctUntilChanged is probably the most interesting of the bunch. As you may infer from the name, it blocks from notifying the subscribers as long as data hasn’t changed. This is where I use some tricks to check if local data is the same with the remote. The v1 and v2 variables are arrays of PizzaViewModel, corresponding to the local and remote data. Every ViewModel has a hashValue property where I convert all of it’s properties into an Int, so I can easily compare if two ViewModels are exactly the same. map turns the array of ViewModels into an array of their hashValue, while sorted just sorts it in ascending order. In Swift, you can easily compare two sorted arrays of integers for equality, and that’s how I can tell if the first set of data is equal to the second.
  • Finally, shareReplay makes sure that each subscriber gets the same data and shares it, so it won’t be run multiple times. I doubt I’ll be subscribing to it more than once, but it’s good to have.

With just a bit of preparation in the Mapper and Query classes, which are necessary, I’ve solved my network problem with just a few lines of code and, to me, in a fairly elegant way. Now, whenever I need a list of pizzas, I can subscribe to the Manager and not worry where it comes from:

Handling Network Errors

Errors are necessary; boring, but necessary. Throughout the course of an application, we have to deal with all kinds of error handling and if it’s not enough, there are network errors too. Something I used to struggle in the past, this time I think I streamlined into a reusable piece of code.

Network Error Screen

The error screen is shown only if there’s no connectivity (no internet or server down) and no local data. When there are local data, I don’t want to disrupt the experience as long as the app is completely usable. With the network code I showed in the previous section, such a test is really simple.

onError will only execute if something bad happened. As I don’t want it to show the error screen if there’s local data, I also check if the pizzaViewModel variable has any value. If it doesn’t, it means there were no local data either, so I’m free to show the error.

The NetworkErrorView is a very simple one with some labels and a button. I’m passing a closure to it as the action of the button, so when it’s tapped, I call the fillWithData method again. It will keep running the same code and showing the same error message until there’s connectivity.

Finally, the error view is passed to the backgroundView of the UICollectionView. It’s usually a good place to put default views, like loading indicators, but it works well in my case. For a more generic approach, one where you can’t use backgroundView, you may still add the error view as a subview of the ViewController and pin its constraints to the edges for a “full screen” effect.

For a complete solution, I probably would have had an ErrorView that laid out the elements and some other views that subclassed it. Maybe I would have had some additional errors like ServerErrorView and JsonParseErrorView, so the user is notified of the exact problem.

Binding to UI Components

The good fellas over at RxSwift have gone through the effort of making most of the UI elements reactive. Not only you can create Observables for your own methods, but you can bind their output with UILabels, UIButtons and so forth.

At first it seems like too much magic and honestly, I’m the skeptic kind that tries to find the trick in “magic trick”. Having stuff abstracted too much makes you feel disconnected to the underlying implementation. Even though you may get that feeling when using reactive bindings, especially with tables and collection views, I’m also sure you’ll spot the benefits.

The binding syntax is as easy as it gets. The code below binds the text of a UILabel to an imaginary Observable method:

Whenever the reactive method has some value, the label’s text will update automatically. This is a great way of having dynamic UIs and I’ve used them extensively in Pizzaiolo. Especially on the shopping cart, where items are removed, quantities changed, and several things need to be recalculated.

Binding a String to a property that expects a String is fine, but not always the case. You may need, for example, to hide the label if the value of some method is zero (an Int). How you gonna do that? We use transforming operators:

Supposing someReactiveMethod returns an Int, map transforms it into a Bool. Only after the transformation it will be bound to the isHidden reactive property of the label, hiding or showing it. You can get very creative with the transforming and combining operators.

RxSwift is very capable of handling more complex UI components like UITableView and UICollectionView in almost the same way as the label we saw. It’s very cool to write a short piece of code as the one below, compile it and see the tableview rendered.

Just pass it the cell identifier (for cell reusability) and the custom UITableViewCell, and it will handle the rest. Not only it will render the table, but it’s reactive too, meaning that whenever the data source changes, the table is reloaded. When you’ll need more control over the delegate methods, such as inserting or deleting rows with animation, there’s RxDataSources. I used it in the CartController for animated row deletion and although it needs quite some boilerplate code compared to the basic binding, it’s still fairly easy to setup.

I’m sure some will see it as black magic and maybe pass, especially for the tables and collection views, and I understand. However, think of the way those components are set up, with all those delegate methods that you’ve written a million times. RxSwift is doing exactly the same thing, only hiding the implementation! Honestly, I never liked those delegates anyway and rarely miss them.

MVVM

I’m sure you’ve used MVC in some way, no matter your background. It has been the de-facto architectural pattern of the past two decades and especially the past one with the rise of Spring, Rails, Django, and the likes.

MVC has a clear separation of concerns by defining three entities: models, views, and controllers. For small applications, that separation works quite well. Most of the time you’ll have those three entities, some helper classes and probably just a bit of business logic. In bigger applications however, there are so many parts that without some experience, you’ll struggle where to put each.

MVVM is an evolution of MVC that tries to solve one specific problem: hiding the Model from the View (or Controller) by having a new interfacing layer, the ViewModel. It may not seem like a big deal, but for flexibility, it certainly is. Having your models called randomly from different parts of your code makes the application tied-in to that storage system (or framework), and in this day and age, it may be a SQL database, a no SQL, API, whatever. The application needs to be as little aware as possible of how data is stored; instead use interfaces that expose those data.

I like to think of ViewModels as Repositories for the View and they’re quite similar in what they’re trying to solve. Instead of building queries, the ViewModel builds how data is output.

The Model

Models aren’t that interesting. A simple class with some properties and maybe a few methods hasn’t much of a story to tell. Databases, on the other hand, are way more entertaining.

Realm is fast, efficient, reactive and all that. Honestly, my general database requirements aren’t trying to store millions of records and access them in nanoseconds. What matters to me the most is simplicity, a word I can’t use to describe Core Data, for example. Realm delivers in every department.

The first thing you do when prepping for Realm, is define Models. They’re actually very simple classes:

Don’t get distracted by the dynamic keyword, as it just exposes the variable to the Objective-C runtime. In the future, when Realm gets completely written in Swift, the syntax will certainly be “swifter”. I’ve also defined a primary key, which is not required, but recommended for efficiency and ease of updating.

With the model in place, we can query the database at will. Realm’s querying syntax will seem very familiar if you’ve used any typical query language. Let’s say I want all pizzas with a price lower than 10:

When the filter needs a variable, as it will frequently be the case, you’ll use a NSPredicate and define placeholders with the %@ characters. In the same fashion, you can use operators like IN, CONTAINS, andLIKE for filtering, @count, @sum or @avg for aggregates, subqueries, comparison operators, etc. It has pretty much everything you’ll need to build even the most complicated queries.

For Pizzaiolo I needed more of a cache solution than a full-fledged database system. Even in this scenario, Realm is fast and thin to not feel like an overhead. Maybe “business requirements” will ask for more in the future and if that’s the case, I can scale it however I like. If I had decided to use a simple cache system, which maybe persisted JSON objects on disk, not only it would have been slower, but completely unscalable.

The ViewModel

As I said earlier, the ViewModel acts as an interfacing layer that hides the Model from Views or Controllers. So why is that? Are we adding some abstraction just for the sake of it?

A typical application will need to access the Model several times to get the data it needs for updating the UI. That’s usually done in the Controller, where those data are prepared, formatted, and passed on to the view for display. Have a price property that will be displayed as currency? You’ll take it from the model, format it in the Controller and finally display it; probably do that 10 other times, spanned in 5 different Controllers. You starting to see the pattern? As I see it, ViewModels have two big advantages:

  • They can prepare, format and combine properties of the Model, so that you don’t repeat yourself, keep consistency and when time comes to change something, you change it only once.
  • Hide the data storage specific implementation from the rest of the application. Models are tied to the data store, but ViewModels aren’t. If you decide to change your storage engine and your Models are affected, you’ll only need to make a few adjustments to the ViewModels. Without such an abstraction, you’d have to go through all of your codebase and change the implementation of the Models, a quite strenuous task.

While the intention may be clear, I know you need some code to fully grasp the concept. Let’s dive in!

Some prefer to write ViewModels that contain Models as an array. When using them, the ViewModel is a single object that holds multiple Model objects. While it has it’s advantages, I personally prefer to map objects one-to-one. Basically, each ViewModel object will hold the Model object that it represents, making the interface much clearer.

With the Pizza Model we defined earlier, let’s write a ViewModel for it:

You’ll notice that it doesn’t do much except to map the model’s properties to its own, and that’s normal. I also have a priceAsCurrency() method that formats an integer to a currency (ex: $12.99) using my own Money helper class. I could have had, for example, another method that formatted the name to a title case. Add to your ViewModels as many methods as it makes sense for your application.

The basic example is pretty fine, but we’re much more ambitious. We can move it one step further by introducing it to ReactiveX, so that we bind the ViewModels properties to those of the Model. That way, whenever the ViewModel is updated, those changes are passed on to the Model too.

The reactive ViewModel will now look like:

More code, but the same idea. First you’ll notice that I’ve declared the properties as Variable, which is a special syntax for BehaviorSubject and makes a variable Observable. Basically, I can subscribe to that variable and listen for value changes. Moving on into the init method, I’ve filled those properties just as I did in the basic example, but this time by initialising them with a Variable. The next lines set up subscribers, so that whenever a property changes, it also updates the model. Finally, I’ve also changed priceAsCurrency to return an Observable instead of a simple value, making it easier to update the UI reactively.

Whatever method you choose to use, reactive or not, the idea of ViewModels remains exactly the same. I’m sure by now you’re starting to see the benefits and imagining how you could integrate them in your applications. That’s good, because they’ll definitely help you design better apps.

We have a ViewModel defined, but how do we use it? Remember in the Rx section where I talked about Managers and how they returned ViewModels? This code:

PizzaManager, if you recall, takes data from the network or locally and maps them to ViewModels. If you imagine having a JSON object from the network, such a code would create an array of ViewModels:

Whenever you have a need for data, either as the data source for a tableview, or just to present some labels on screen, you’ll get them from ViewModels. This time you’ll not be tied to the data storage system or write the same formatting code a million times.

Storyboards vs Code

We as humans are visual learners. Our brains tend to memorise way more easily pictures than written words. As such, I really wanted to like Storyboards and somewhat, deep in my heart, I believe I still do.

The idea of Storyboards as a design tool is fantastic. You can lay out UI elements and change their properties just like you do in a graphic software, without having knowledge of code or how those elements work. A developer can entrust the designer to pixel-perfectly build the screens directly in Xcode, and not some special software that needs translation. It would have been great, but as I see it, Storyboards are plagued by some essential problems.

Every design tool I’ve used has some form of symbols. Basically, you create something that you know is going to be reused a lot, so you encapsulate it in a symbol. Sketch has modernised that idea in amazing ways; symbols have overridable properties that can be changed on each instance, and can be nested, allowing for some very creative encapsulation. Would that be too much to ask for Storyboards?

Before you curse me, yes I know that views can be reused in Storyboards, but it’s far from perfect. Yes, you can create standalone XIB files (or separate Storyboards) or even containers for common ViewControllers. Both methods feel like hacks and don’t make for a pleasant setup. More importantly, they don’t provide any of the modern features I talked about.

For Pizzaiolo I knew I would have some views and buttons that would be used multiple times throughout the application. Those reusable views are laid out in code, while ViewControllers and static elements like tables or collection views are set up in Storyboards. They look empty and definitely not designer friendly, but it’s the middle ground for having reusable views without too much boilerplate.

Storyboard

Coding the UI

Coding views is definitely more tedious than laying them out graphically. I don’t care about the amount of code, as I’m used to that. It’s the add something, compile and run, make some changes, repeat. With code there are no visual cues to what you’re building, so you have to go to a few iterations until it looks perfect. Compare that to Storyboards where you throw in some views exactly where you want them and get them right in the first run.

However, programmatic views have 3 major advantages:

  • They can be reused anywhere without a single line of boilerplate. Just initialise it and you got a fresh UI component.
  • Elements and properties can be overridden in every possible way.
  • Nested symbols are not only possibly, but very easy to achieve.

Now that you know they’re good, you may be wondering how a programmatic view looks like. In all fairness, nothing out of the ordinary, and if you’ve ever created a UIView or a UILabel in code, it should look very familiar.

This is a “AddToCart” view that I’m using for Pizzaiolo:

Let’s break it down. The price and button properties are self executing blocks that setup respectively a UILabel and a UIButton. The two init methods, one for creating the view programmatically and the other in Storyboards, call the setupViews() method, a convention I use in all my views. In there, I add those views to the main view (remember, AddToCartView is a subclass of UIView) and set Auto Layout constraints.

Whenever I need an “AddToCart” component, it’s easy as pie to call it. I can modify its properties, because as you may notice, I haven’t declared them private:

As any other view, I can embed it into other components, creating the concept of nested symbols:

Isn’t that great?! You can divide your application into small components that specialise into very specific tasks. Programmatic views allow it by having absolutely no boilerplate to initialise, override, or nest. If you think it, component-based UIs have been in trend for some years now and for a good reason. I believe that Storyboards have lured many developers into its graphical approach, while having them forget reusability.

Auto Layout

Apple advices to use the Interface Builder to create constraints and they’re definitely right: creating constraints via code is a pain. Neither the newer (iOS 9+) NSLayoutAnchor, nor the older NSLayoutConstraint or the even stranger Visual Formatting Language come for your help. They’re verbose and unintuitive, to say the least.

Fortunately, there are many libraries that try to fix something Apple should have many years ago. I’m personally a fan of SnapKit and that’s what I’ll be shortly talking about. It’s so intuitive that it doesn’t need more than a couple minutes of reading the docs to become an expert-level. Really!

Imagine having an UIImageView and wanting it to snap on the sides of it’s parent view. Basically, you’d have to create leading, trailing, top and bottom constraints. This code will do:

Can be it be more simple than that? Now, for a more typical layout, let’s say we have the same image, but want it to be a square of 100 pixels and centre horizontally and vertically. Easy enough:

There’s many more fluent methods like that for basically every requirement. Even if you’re not going to use programmatic views exclusively, whenever the need comes to code some constraints, just use SnapKit. It’s small and unobtrusive.

Animations

I’m a sucker for animations. I love anything from moving squares to Disney’s fantastic orchestration of a million things animating at the same time. But, as we’re in the iOS realm, what I really like are sequential, easy to follow animations that enhance the UI and UX.

iOS has quite a few ways to animate, from simple manipulations of a view’s bounds or centre, to 3d transforms, keyframe animations, etc. I prefer using CGAffineTransform as it offers a very simple interface to animating translation, scaling and rotation.

A Simple Parallax

When swiping between pizzas, I wanted some kind of animation just to spice it up a bit. Tried a few things and finally settled on a simple “parallax” effect, where different components come on screen at different speeds. As you’ll see below, the animation is very subtle, so it complements the design without taking too much focus. It’s actually so subtle that I had to slo-mo it. These are my kind of animations: you can’t immediately tell, but you can feel them.

Parallax effect in slow motion

Technically, each screen is a custom cell of a UICollectionView that holds the pizza image, text and button. To achieve the effect, I needed to know before hand in which cell it is going to scroll to. Luckily, the willDisplay cell method of the collection view gives exactly that: the cell that it is going to display. When the swipe starts, I hold a reference to that cell and run the animation in scrollViewDidScroll.

The animation code is fairly simple:

position is a floating point number that is calculated based on the relative scroll position. Adding some different multipliers to that value animates the elements with different speeds, thus creating the simple parallax effect.

Custom Transitions

Aren’t we all bored from that same “push” transition? We’ve seen it a trillion times in almost any app, especially iOS’s default ones. I’m using it myself, obviously, because having a navigation controller makes sense. However, I had a case where a “push” wouldn’t make justice to what I was trying to express.

The shopping cart icon sits at the right side of the navigation bar. When that button was clicked, my intention was to slide the screen down partially to reveal the cart contents. Such a concept can’t be achieved either with a push, or one of the very limited modal transitions.

Slide Custom Transition

I’ve created custom segues in the past, but wasn’t really happy with the process. The unwinding (reverse animation) is more of a hack and I’ve never understood why it hasn’t got a simpler solution. Enter UIViewControllerAnimatedTransitioning.

Not having much experience with them, I based my implementation in a tutorial by AppCoda. Once I read their code, the general idea is very simple. Basically, the transition class is exposed to the from and to controller, which are the presenting and destination controllers. There’s also a containerView that’s really helpful to add additional views while the transition is happening. For example, in my case (and the tutorial’s), I take a screenshot of the current screen and add it to the containerView, so it persists when the transition finishes.

Next time your app needs a custom transition, don’t go lazy on it. Just remember to use them where it makes sense, not just to showoff some cool animation. Users care for your content, not your animation skills.

Launch Screen

Apple’s Guidelines tell clearly that Launch Screens should be used to give the impression that the app has already loaded. It should be the first frame of the home screen, stripped from images, text and any other dynamic content. Actually that makes total sense and in production apps I’ve followed that guideline like a fanatic. For Pizzaiolo however, I didn’t care that much. Yes, I also like to live dangerously!

Launch Screen Animation

The Launch Screen Storyboard file can’t be linked to a ViewController, thus making it impossible to animate. I wanted to rotate the pizza on its axis while the app was loading, but no, can’t do that! Had to settle for a static image of the pizza base as the first frame, so I could link it to the rest of the animation.

When the Launch Screen finishes, it immediately goes to the root view controller, which I’ve creatively named LaunchScreenController. In there I run the actual animation that starts exactly like the Launch Screen. The rest continues with the peel entering the frame and taking the pizza together with the whole screen. I managed to do it with a custom transition that moves the presenting ViewController off screen and by animating the cornerRadius.

It make look cool, but I wouldn’t argue that’s an effective way of opening the app. It may be fine for launches, but definitely not when switching between apps, as you’d see the same animation over and over. Probably not worth it for production.

Loading Placeholder

Not sure if Facebook invented these, but I’m sure I’ve seen it there for the first time. It’s such a great idea that I wish I would have thought before them, so I could sell it for millions. Now I’d be Mr. Placeholder! If you don’t know what I’m talking about, it’s the placeholder that shows while posts are being loaded:

Facebook Loading Placeholder

I could use that same idea for Pizzaiolo and the most important section is the Pizza Selector. In there, I load a bunch of pizzas together with their photos, so it may take a couple of seconds. During that time, instead of a typical UIActivityIndicator, I can show a nice placeholder.

Pizza Loading Placeholder

What I did was to replicate the pizza cell, so that the elements would stay in the same position. The image was replaced by a UIView with a corner radius that equals the view’s width divided by 2, a trick to transforming a square to a circle. The labels are the same, but without text and with a light grey background colour, making them look like blocks. During loading, that view is inserted as the backgroundView property of the collection view, which is perfect for such stuff. Oh yeah, and it animates too with a simple pulse effect.

Closing Thoughts

Making an iOS app isn’t that hard. Sure, some grinding with the SDK is inevitable, but that’s true for almost any platform. Once you get the hang of the general idea, those delegates, actions, frames and how UI components behave, it’s pretty straightforward to build apps of any complexity. It just needs some of your time and investment, which I believe is worth it, because it’s a truly nice platform to work with.

Pizzaiolo is my seventh complete iOS app, so I believe I’m past that grinding phase. However, new challenges present themselves on every step. Now I’m thinking more about architectural choices, things that streamline the process, UI details and animations, and stuff like that. It’s more of moving from what I’m comfortable with to the uncomfortable, but potentially better.

It took me the afternoons of a month and a half to build the app, from design to finish. Considering the simplicity, it’s a relatively long journey in which I had to tackle RxSwift and make design decisions I hand’t thought of in the past. That’s good because not only I learned a great deal, but had a lot of fun on the way. To me, that’s on top of the importance stack.

Hopefully my journey will help you in deciding to invest in iOS development or learn a few of my tricks. You know, it’s a beautiful thing to create interactive stories with such a limited screen estate. It’s even better when you do it right!

--

--