Coding An App For Spotify In Swift

If you are looking to become an iOS developer, there are some fundamental skills worth knowing. First, it's important to be familiar with creating table views. Second, you should know how to populate those table views with data. Third, it's great if you can fetch data from an API and use this data in your table view.

  1. Coding An App For Spotify In Swift 2020
  2. Free Spotify App
  3. Spotify App For Laptop

The third point is what we'll cover in this article. Since the introduction of Codable in Swift 4, making API calls is much easier. Previously most people used pods like Alamofire and SwiftyJson (you can read about how to do that here). Now the Swift way is much nicer out of the box, so there's no reason to download a pod.

The very initiative with which Swift was created was Apple’s “Anyone Can Code”. Clearly, if you’re looking to get started in app development, Swift is your best programming language. Some of the best apps you’ve heard of including Uber, Lyft, Square and Airbnb use Swift as their primary programming language for iOS apps.

Let's go through some building blocks that are often used to make an API call. We'll cover these concepts first, as they are important parts to understanding how to make an API call.

  • Completion handlers
  • URLSession
  • DispatchQueue
  • Retain cycles

Finally we'll put it all together. I'll be using the open source Star Wars API to build this project. You can see my full project code on GitHub.

Disclaimer alert: I am new to coding and am largely self-taught. Apologies if I misrepresent some concepts.

Completion handlers

Remember the episode of Friends where Pheobe is glued to the phone for days waiting to speak with customer service? Imagine if at the very start of that phone call, a lovely person called Pip said: 'Thanks for calling. I have no idea how long you'll need to wait on hold, but I'll call you back when we're ready for you.' It wouldn't have been as funny, but Pip is offering to be a completion handler for Pheobe.

You use a completion handler in a function when you know that function will take a while to complete. You don't know how long, and you don't want to pause your life waiting for it to finish. So you ask Pip to tap you on the shoulder when she's ready to give you the answer. That way you can go about your life, run some errands, read a book, and watch TV. When Pip taps on you on the shoulder with the answer, you can take her answer and use it.

This is what happens with API calls. You send a URL request to a server, asking it for some data. You hope the server returns the data quickly, but you don't know how long it will take. Instead of making your user wait patiently for the server to give you the data, you use a completion handler. This means you can tell your app to go off and do other things, such as loading the rest of the page.

You tell the completion handler to tap your app on the shoulder once it has the information you want. You can specify what that information is. That way, when your app gets tapped on the shoulder, it can take the information from the completion handler and do something with it. Usually what you'll do is reload the table view so the data appears to the user.

Here's an example of what a completion handler looks like. The first example is setting up the API call itself:

Now we want to call the function fetchFilms. Some things to note:

  • You don't need to reference completionHandler when you call the function. The only time you reference completionHandler is inside the function declaration.
  • The completion handler will give us back some data to use. Based on the function we've written above, we know to expect data which is of type [Film]. We need to name the data so that we can refer to it. Below I'm using the name films, but it could be randomData, or any other variable name I'd like.

The code will look something like this:

URLSession

URLSession is like the manager of a team. The manager doesn't do anything on her own. Her job is to share the work with the people in her team, and they'll get the job done. Her team are dataTasks. Every time you need some data, write to the boss and use URLSession.shared.dataTask.

You can give the dataTask different types of information to help you achieve your goal. Giving information to dataTask is called initialization. I initialism my dataTasks with URLs. dataTasks also use completion handlers as part of their initialization. Here's an example:

dataTasks use completion handlers, and they always return the same types of information: data, response and error. You can give these data types different names, like (data, res, err) or (someData, someResponse, someError). For the sake of convention, it's best to stick to something obvious rather than go rogue with new variable names.

Let's start with error. If the dataTask returns an error, you'll want to know that upfront. It means you can direct your code to handle the error gracefully. It also means you won't bother trying to read the data and do something with it as there is an error in returning the data.

Below I am handling the error really simply by printing an error to the console and exiting the function. There are many other ways you could handle the error if you wanted to. Think about how fundamental this data is to your app. For example, if you have a banking app and this API call shows users their balance, then you may want to handle the error by presenting a modal to the user that says, 'Sorry, we're experiencing a problem right now. Please try again later.'

Next we look at the response. You can cast the response to be an httpResponse. That way you can look at the status codes and make some decisions based on the code. For example, if the status code is 404, then you know the page was not found.

The code below uses a guard to check that two things exist. If both exist, then it allows the code to continue to the next statement after the guard clause. If either of the statements fail, then we exit the function. This is a typical use case of a guard clause. You expect the code after a guard clause to be the happy days flow (i.e. the easy flow with no errors).

Finally you handle the data itself. Notice that we haven't used the completion handler for the error or the response. That's because the completion handler is waiting for data from the API. If it doesn't get to the data part of the code, there's no need to invoke the handler.

For the data, we are using the JSONDecoder to parse the data in a nice way. This is pretty nifty, but requires that you have established a model. Our model is called FilmSummary. If JSONDecoder is new to you, then have a look online for how to use it and how to use Codable. It's really simple in Swift 4 and above compared to the Swift 3 days.

In the code below, we are first checking that the data exists. We are pretty sure it should exist, because there are no errors and no strange HTTP responses. Second, we check that we can parse the data we receive in the way we expect. If we can, then we return the film summary to the completion handler. Just in case there is no data to return from the API, we have a fall back plan of the empty array.

So the full code for API call looks like this:

Retain cycles

Coding An App For Spotify In Swift 2020

NB: I am extremely new to understanding retain cycles! Here's the gist of what I researched online.

Retain cycles are important to understand for memory management. Basically you want your app to clean up bits of memory that it doesn't need anymore. I assume this makes the app more performant.

There are lots of ways that Swift helps you do this automatically. However there are many ways that you can accidentally code retain cycles into your app. A retain cycle means that your app will always hold on to the memory for a certain piece of code. Generally it happens when you have two things that have strong pointers to each other.

To get around this, people often use weak. When one side of the code is weak, you don't have a retain cycle and your app will be able to release the memory.

For our purpose, a common pattern is to use [weak self] when calling the API. This ensures that once the completion handler returns some code, the app can release the memory.

DispatchQueue

Xcode uses different threads to execute code in parallel. The advantage of multiple threads means you aren't stuck waiting on one thing to finish before you can move on to the next. Hopefully you can start to see the links to completion handlers here.

These threads seem to be also called dispatch queues. API calls are handled on one queue, typically a queue in the background. Once you have the data from your API call, most likely you'll want to show that data to the user. That means you'll want to refresh your table view.

Table views are part of the UI, and all UI manipulations should be done in the main dispatch queue. This means somewhere in your view controller file, usually as part of the viewDidLoad function, you should have a bit of code that tells your table view to refresh.

We only want the table view to refresh once it has some new data from the API. This means we'll use a completion handler to tap us on the shoulder and tell us when that API call is finished. We'll wait until that tap before we refresh the table.

The code will look something like:

viewDidLoad vs viewDidAppear

Finally you need to decide where to call your fetchfilms function. It will be inside a view controller that will use the data from the API. There are two obvious places you could make this API call. One is inside viewDidLoad and the other is inside viewDidAppear.

These are two different states for your app. My understanding is viewDidLoad is called the first time you load up that view in the foreground. viewDidAppear is called every time you come back to that view, for example when you press the back button to come back to the view.

If you expect your data to change in between the times that the user will navigate to and from that view, then you may want to put your API call in viewDidAppear. However I think for almost all apps, viewDidLoad is sufficient. Apple recommends viewDidAppear for all API calls, but that seems like overkill. I imagine it would make your app less performant as it's making many more API calls that it needs to.

Combining all the steps

First: write the function that calls the API. Above, this is fetchFilms. This will have a completion handler, which will return the data you are interested in. In my example, the completion handler returns an array of films.

Second: call this function in your view controller. You do this here because you want to update the view based on the data from the API. In my example, I am refreshing a table view once the API returns the data.

Third: decide where in your view controller you would like to call the function. In my example, I call it in viewDidLoad.

Fourth: decide what to do with the data from the API. In my example, I am refreshing a table view.

Inside NetworkManager.swift (this function can be defined in your view controller if you'd like, but I am using the MVVM pattern).

Inside FilmsViewController.swift:

Gosh, we made it! Thanks for sticking with me.

In this post we will try to re-create the Spotify home screen layout in Swift programmatically. Why programmatically? I think it's always good to know how to build things in different ways, and I like to write code to do things programmatically. These skills are especially helpful if you are working with team or using version control.

This is the actual home screen of Spotify's mobile app. So to achieve this kind of layout, we will be using UICollectionView, and we may use TabBarController as well to create the tab navigator.

Basic requirement : First make sure you have Xcode +10 installed and swift +4.

Let's start by creating a new Xcode project using Xcode:

And the first thing we need to do in ViewController.swift is change the superClass to UICollectionViewController instead of UIViewController because our class will be based on collectionView.

If you try to run the app the build will fail. We need to add some code to the AppDelegate.swift file within the didFinishLaunchingWithOptions function past this piece of code before the return statement:

And the code should look like this:

Now you should be able to run the app and see the backgroundColor changed to purple:

Coding

The next step is to distribute the layout and divide the space equally between the sections.

Let's define the methods of our CollectionView.

The steps:

  • Register a reusable cell with unique identifier
  • Define the number of the items in the section
  • Use the the registered cell

To use some of CollectionView methods we need to always conform to UICollectionViewDelegateFlowLayout as a superClass and to get the autoComplete of the methods. So let's start with registering the CollectionViewCell.

Inside View.DidLoad() we call the collectionView.register() method to register the reusable cell:

Then we define the number of cells we will have inside the collectionView using numberOfItemsInSection. For now we just need to make it 5 items:

The next step is to define the reusable cell using cellForItemAt that should return UICollectionViewCell and have a unique id called cellId. The code looks like this:

The full code should look like this:

You should be able to see 5 items with red backgrounds on the screen:

Add a custom width and height to the cells

Now we need to place the cells in the correct order and give them a width and height. Each cell will take the width of the screen as width.

We are lucky to have sizeForItemAt method so we can give the cells a custom width and height. It's a method that should return a CGSize type:

So we made the Cell take the width of the screen by using view.frame.width and a custom height with is a CGFloat type.

Now you can see the result below in your Simulator :

Everything looks good so far. This time let's create a custom cell that can be reusable. Create a new Swift file named CustomCell:

CustomCell.swift should look like this below:

Now the next things we have to do is to modify two methods to support the reusable cell, collectionView.register and cellForItemAt. Let's first modify the register method. Replace UICollectionViewCell.selfwith CustomCell:

Next we need to cast cellForItemAt to conform to CustomCell like below:

Coding An App For Spotify In Swift

If you run the app probably you won't notice any change, so give the CustomCell a backgroundColor backgroundColor = .yellow. Don't forget to remove the line cell.backgroundColor = .red in cellForItemAt. You should see the background color changed to yellow ?

Now it's time to put some salt into CutomCell :D

If you look at the Spotify home screen, each section which is a CustomCell in our example contains a section title, sub cells, and is horizontal:

Add a section title

Let's add a title label to the cell. Create the titleLabel element inside the CutomCell class:

Then add the element to the view inside init() block:

If you run the app you won't see any changes, and that's because we didn't put any constraint to the element yet. So let's add some constraints – add this property lb.translatesAutoresizingMaskIntoConstraints = falsetotitleLabel to be able to apply constraints to the element:

After we add titleLabel to the view, we define the constraints:

Always make sure to add .isActive = true property – without it the constraint won't work!

Before we move on to the next part, let's first change the background color of the screen to black and also remove the yellow color for the cells:

Now comes the big part: putting sub cells into each cell. To achieve that we are going to add a CollectionView inside CustomCell.

To add a CollectionView inside UICollectionViewCell we need to add properties UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, and UICollectionViewDataSource as superClass to CustomCell.

Let's create the collectionView element as any simple view:

Notice that we add layout to the collectionView as layer in the initializer as we did the first time with the viewController.swift. Here we also specify the direction of the FlowLayout to be .horizontal.

Let's add the collectionView element to the view as subView.

We gonna make a function that do that for us to make the code a little bit cleaner.

Make sure to set delegate to self for the collectionView and the dataSource as well:

collectionView.dataSource = self

collectionView.delegate = self

Then call the function within init block.

Xcode will display some errors if you trying to build the app because we are not conforming to UICollectionViewDelegate and UICollectionViewDelegateFlowLayout protocols. To fix that we need first to register the sub cell as a reusable cell.

Create a variable at the top of the class and give it a name of cellId so we can use it when we need the cell identifier:

Free Spotify App

let cellId : String = 'subCellID'

Now we're missing two more methods to make the errors go away: numberOfItemsInSection that define the number of cells in the section and cellForItemAt that define the reusable cell. These methods are necessary for collectionView to work properly:

The results should look like this:

As you can see, the collectionView are in purple as background and sub cells are yellow.

The last things we can do before ending this article is make subCells have the height of the section and as width. Again we are using sizeForItemAt to define the height and the width of the cell .

And here we are ?:

NICE! I'm gonna stop at this point so this post isn't too long. I'll make a second part where we are going to add some mocked pictures and fill it with some data.

Full source code ? here

Please please if you have any additions, questions, or corrections, post it in the comments below ? or hit me up on Twitter.

Spotify App For Laptop

Subscribe to my email list to be notified when the second part of this tutorial is published