top of page

What I learned by developing and publishing my first iOS app - Part 1

Writer's picture: Eric PalmaEric Palma

Updated: Jan 3

Before I ever developed my own app, I had no idea just how much I still had to learn even though I knew the basics of programming. By developing and publishing my first app I learned many important concepts and lessons related to iOS development which I will go over in this post.


By sharing my learnings I hope to help others who have not yet gone through the process of developing their own app get prepared ahead of time. Therefore, the topics I will go over are mainly geared towards those who have basic programming skills, but don’t yet fully understand how to use their knowledge and skills to build a fully functional iOS app.


This post is part 1 of 2. Part 1 focuses more on code and architecture, whereas part 2 will focus more development tools.


Asynchronous vs Synchronous Programming


Chances are, if you are building an app that makes network calls, uses a database, or does any kind of heavy processing, you will need to use asynchronous programming. I am going to define what synchronous programming is first, and then what asynchronous programming is.


In synchronous programming, the entire program gets executed serially, meaning each line of code gets executed in order over time. This is what most beginner developers are used to. What this means is that when a line of code in your program calls a function, it has to wait for the function it just called to finish before it continues onto the next line.





In asynchronous programming, the program is not always executed serially, instead, the code may get executed in a somewhat arbitrary order. Taking our example of calling a function, in asynchronous programming the line of code calling an asynchronous function is not blocked waiting for the called function to finish, rather it can continue executing the next task (next line of code) immediately.





Now that we have a basic understanding of what synchronous vs asynchronous programming is, let us look at a simple example.


Say we have an application that displays a list of movies, it allows users to scroll through the list, and each movie has a download button that begins downloading the movie from a server. First I will describe how this application will work with synchronous programming only, and then I will describe how it will work if asynchronous programming is used.


Synchronous


Say our user is on their phone scrolling through the application looking for a movie to download. When the user sees a movie they wish to download, they click the download button next to the movie. At this point the movie downloading code begins executing, and since we used synchronous programming, the user must wait for the download task to finish before they can do anything else. This means the user cannot keep scrolling in the meantime to look for another movie to download, or perform any other action for that matter. Again, because our entire program is synchronous, it needs to finish one task before moving on to the next.


Once the movie download task completes, the user can continue scrolling. With this synchronous programming example, at any given moment the user may either be scrolling through the list of movies, or downloading a movie, but not both.


Asynchronous


Now let's see what our application would behave like if it used asynchronous programming. Again, say our user is scrolling through a list of movies to download on their phone. The user finds a movie they like and clicks the download button, so the movie downloading instructions begin executing. At this point, the user can keep scrolling through the list of movies WHILE the movie downloading task is running.


This is possible because the program starts the movie download task and returns immediately without the need to wait for the download task to complete. The code to download the movie data is run asynchronously from the code that called it. Meaning, it does not matter to the caller whether it returns immediately or at a later time. In this way the application code for handling user scrolling continues running while the download task runs. Usually the calling code will pass what is called a call back method to the asynchronous code, so that once the asynchronous code completes, it has a way to let the caller know.


One important note, I have not mentioned one important detail here, and that is the thread or threads that are used in these examples. Asynchronous programming usually involves two or more threads. We discuss threads in the next section below.


If this is all sounding confusing to you, don’t worry, it took me a while to really wrap my head around this too. In all fairness, this topic deserves an entire article to itself, however the point of including it here is to make you aware of it because this is something I can almost guarantee you will encounter. This way you can begin learning more about asynchronous programming so you are prepared.


Here is a useful article going into more detail on the topic:



The Main Thread


If you have no idea what threads are yet, you can think of them as a set of instructions designed to be scheduled and executed by the CPU together sequentially. In both iOS and Android, there is a thread called the Main thread, which is in charge of, among other things, executing instructions for responding to user input like touches and gestures, as well as, very importantly, updating the User Interface (UI).





For example, when your phone updates the screen you are currently interacting with, it is scheduling the instructions for doing the actual updates to the screen on the main thread. All UI updates must be done on the main thread. This is a very important thing to understand and remember.


Let's take another look at our example video application from the last section, this time, it is using asynchronous programming along with two threads, the main and a background thread. Again, let's imagine that you are scrolling through the list of movies, and you click the download button on one of them. What happens here is that the instructions on the main thread will handle the input (download button clicked) and then call the movie download code asynchronously, then they will go back to handling any other UI related updates, such as the user scrolling.


In practice, code like the one to download movies from a server is executed on a background thread. So when the instructions on the main thread call the instructions for downloading movies, they are explicitly scheduled on the background thread using a library call. This is made possible through asynchronous programming, in this way the main thread can continue executing instructions while the background thread goes off and begins working, in this example it will download a movie. Once the background thread finishes it uses some sort of call back method to notify the main thread that it has completed.


It is important to note that if asynchronous programming and multiple threads were not used, what would happen is the app would seem sluggish, because it first needs to finish running the instructions for downloading the video before it can process the instructions to handle scrolling. But since we are using multiple threads, the app seems responsive.


To highlight why the main thread is so important, here is an example of an error that I am sure many first time mobile developers, especially those new to software development, will likely encounter every now and then:


Main Thread Checker: UI API called on a background thread: <more detailed description goes here>

The above is an error outputted on the Xcode console, after your app likely just crashed because a thread other than the main thread was used to run a UI API instruction. In short, what happens is that Apple’s Main Thread Checker tool ensures that certain APIs are not used from a background thread. The main two of these APIs being UIKit and SwiftUI. UIKit and SwiftUI are Apple’s APIs for UI development, and remember, UI instructions need to run on the main thread.


This error could be triggered in our example application, if for example, we tried to make updates to our UI directly from our background thread, possibly after we finished downloading a movie.





The fix for these sorts of errors is to ensure that if you are working with multiple threads, you ensure to explicitly call UI instructions on the main thread only. In iOS this can be done by using DispatchQueue for example:


DispatchQueue.main.async {
	// The UI related code goes here
}

The above code dispatches the UI related code onto the main thread asynchronously for scheduling and execution.


Application Lifecycle


When I began programming my first iOS application, application lifecycle was one of the first topics I had to learn and get comfortable with real fast. Application lifecycle refers to the different states your application will be in throughout its use on the phone. Here is a useful graphic borrowed from Apple’s documentation describing an iOS application’s lifecycle:




Your app may be in any of the above states dependent on whether it is currently being used, not being used, or terminated by the operating system for a number of reasons. It will constantly be switching back and forth between the different states, so you will need to learn how to respond to each change in state.


Apple’s UIKit provides APIs that allow you to respond to each change in state. Usually each change in state allows you to respond before, during, and after the change in state is completed. In this way your app is able to prepare for launch, or termination.


To get an idea of how an application may respond to changes in its state, let's look at how an app that uses a database to store user data locally may respond. If the app is in the terminated state and is about to be moved to the active state, it may respond to this change by ensuring that its database is initialized properly. If instead it is going from the active state to the terminated state, it may respond to this change by ensuring all its data is stored in the database, so that no data is lost once the app is terminated.


To learn more about this topic, I have linked references for iOS and Android below.


iOS


Android


Architectural Patterns


Architectural patterns are like the blueprint of your application, they describe the high level structure of your application, the components in it, and how they interact with each other. Architectural patterns do not get into the implementation, as that will vary from application to application.


Two patterns that will be very useful to learn for mobile development are the Model View ViewModel (MVVM) and the Coordinator pattern.


Model View ViewModel


The MVVM pattern helps to separate the applications business layer from the presentation (UI) layer. The business layer is what differentiates your app from other apps by providing useful and unique functionality to users. This is the layer that holds your apps data and likely performs some custom logic on it. The presentation layer is what users see, it is the user interface that is used to interact with the application.


Here is a simple graphic describing the MVVM pattern:




Coordinator


The coordinator pattern is used to handle navigation. In iOS, if you don’t use the coordinator pattern, this responsibility will fall onto your UIViewController classes. For simple cases, this is probably fine, however it will not scale very well as the UIViewController classes will grow substantially and will not have good separation of concerns.


By using the coordinator pattern we move that responsibility to separate specialized classes called Coordinators. This enforces separation of concerns and makes it easy to change the navigation logic of our applications.


Below is a simple illustration of the Coordinator pattern:




Here are some useful references:

MVVM:

Coordinator:


Most things don’t need to be built from scratch


Before I developed my first iOS app, I believed that building a user interface would be a very complex task. I believed this because I had the idea that I would need to build out the basic user interface components from scratch and use complex algorithms to render them on the screen. I also thought the same for other services such as networking and storage. I was so wrong.


The great thing about platforms such as iOS and Android is that they’ve already done the heavy lifting by taking care of the most low level, complex parts that make applications work on the phone. They expose the basic building blocks you need to build your application as an Application User Interface (API).


For example, in iOS, the APIs you will be using the most to build out user interfaces are UIKit and SwiftUI. They provide basic UI components such as text fields and buttons, which you can configure to fit your specific needs.


This is not only true for UI development, the same is true for other important functionality such as networking and databases. You won’t have to worry about starting from absolute scratch. This allows you to focus on what makes your application unique.


Read the Documentation


In the section above I said that Apple and Android provide APIs to help simplify your development tasks. Well, this will only be true if you know how to use them correctly, and to do that, you MUST read the documentation.


Yes you can figure out how to use the APIs by trial and error, but this is such a huge time waster. In fact, for some tasks there is more than one way to get the job done, so it’s better that you understand the tradeoffs so you don’t pay the price later down the line.


Too many times I thought it would be quicker if I looked up how to modify a UITextField for my iOS app on Stack Overflow. I would later find out that if I just took a couple minutes to look at the documentation for UITextField, I would’ve quickly found out how to accomplish what I wanted in a more efficient way. The documentation provides examples of the most common uses. If you have a non common case, reading the documentation will allow you to figure out how to go about solving it.


If you have never developed a mobile application before, I highly recommend you check out the documentation links I provide below. They do a great job of explaining how to get started developing for each respective platform.


iOS Developer Documentation:

Getting started:


Android Developer Documentation:

https://developer.android.com

Comments


Commenting has been turned off.
Site
Join the growing community of iOS engineers who are taking their skills to the next level.

© 2025 Curious Algorithm. All rights reserved.

bottom of page