Making a Podcast App From Scratch

Build a podcast app completely from scratch. Along the way we’ll deal with implementing some custom UI, transitions, networking, local persistence, and of course audio playback.

Length: about 9 hours.

Start Series

Installments

1. Intro

Subscribers only

We’re kicking off a brand new series on building a podcast app from scratch. Along the way we’ll deal with implementing some custom UI, transitions, networking, local persistence, and of course audio playback.

2. New Project Setup & Theming

Subscribers only

We start from a blank project template, then add our first storyboard and tab bar controller. We also introduce a mechanism for skinning the app with a Theme type.

3. Storyboard References

Subscribers only

We start out by creating our first view controller (Search) by creating some structure to keep things organized by logical function (rather than by subclass) and create a storyboard to hold each tab. The main storyboard then uses Storyboard References to keep things tidy.

4. Reusable Views

Subscribers only

In this episode we start building our first table view cells. We then build a protocol to represent Reusable Views, such as UITableViewCells. With this protocol you can supply a simple type reference and the reuse identifier and casting happens for you. Leveraging Swift's protocol extensions allows you to leverage your conventions to write cleaner, safer code.

5. Styling Custom Cells

Subscribers only

In this episode we add our tableview cell styling to match the design, using autolayout to arrange the views and using the Xcode View Debugger to find and fix a visual glitch when using dark background cells.

6. Working with Remote Images

Subscribers only

Working with images from the network is such a common task in iOS development. In this episode we'll cover a useful library called Kingfisher, which gives you a simple API for downloading and caching images from the network. We also look at two ways for configuring our image view, one using User-Defined Runtime Attributes and the other by using awakeFromNib in code.

7. Creating an API Client

Subscribers only

It's time to start talking to external APIs to get the data we want to display in the app. We start by exploring the API we want to consume with Paw, a useful macOS app. We then create a simple API client class that abstracts most of the boilerplate logic around how to handle the various URLSession outcomes.

8. Parsing JSON into Models

Subscribers only

In this episode we take the response from the top podcasts feed and decode the JSON into models using Codable.

9. Displaying Search Results and Recommendations

Subscribers only

In this episode we build another API client to search for podcasts matching a term and customize the UI and behavior of the search bar. We display the recommended podcasts first, then when a user types in a term we show the matching podcasts from the iTunes API.

10. Parsing RSS and Atom Feeds

Subscribers only

To get the information we need for the Podcast Detail screen, we’ll have to get the feed URL and parse it. There’s no built-in Codable support for XML, so we’ll look at using FeedKit to parse the feeds and extract the relevant information we need.

11. Podcast Detail Screen

Subscribers only

In this episode we start laying out the Podcast Detail screen. We'll start by using an embedded view controller for the header portion, which contains all of the top-level information about the podcast. We'll then see how we can utilize this child view controller to contain all of our outlets and how to pass data from the parent view controller to the child.

12. Custom Gradient Background

Subscribers only

In this episode we create a custom UIView subclass that draws a gradient overlay. This allows us to overlap the podcast information above the artwork slightly.

13. Padded Label and Separator View

Subscribers only

In this episode we create some more custom @IBDesignable views, this time for a padded genre label where we use the intrinsicContentSize to make a label take up more space and give itself a little padding. We also create a separator view that draws a thin line to separate sections visually.

14. Making a Custom Subscribe Button

Subscribers only

In this episode we customize our call-to-action Subscribe button. Using @IBDesignable and Interface Builder we can preview how it looks in the various button states without having to recompile and run in the simulator every time.

15. Refactoring to a Data Manager

Subscribers only

In this episode we clean up some autolayout warnings, implement some changes to support dynamic text, then move our attention to presenting the podcast detail screen when tapping on search results. Since the data is coming from various places we introduce a Data Manager to move that responsibility out of the view controller.

16. Adding Episode Cells

Subscribers only

In this episode we extract episode information from the podcast feed and render them as cells on the podcast detail screen.

17. Polish and Cleanup

Subscribers only

We have some housekeeping to do in this episode. We also want to add a little polish to the podcast detail screen so that it doesn't resemble a stock table view driven app. We also need to clean up the data model a bit in preparation for persistence, and we also want to remove the pesky html tags that show up on the podcast and episode descriptions.

18. Setting up Core Data to Save Subscriptions

Subscribers only

In this episode we set up a Core Data model for persisting podcast subscriptions. We'll cover the various ways Xcode generates model classes for us and work on saving and loading podcast subscriptions so that the subscribe button behaves as it should.

19. Player Screen

Subscribers only

We've spent a lot of time dealing with the data, networking, architecture, and overall theme of our podcast app, but we haven't yet written a player! So in this episode we start the process of designing our player screen. We'll start by adding all of the controls and views to our PlayerViewController, wire everything up, and customize the look & feel to match our Sketch design.

20. Audio Playback

Subscribers only

In this episode we implement one of the core functions of a podcast player: playing audio! Using AVPlayer we load up the track and observe its progress so we can update the UI to reflect time progressed, time remaining, as well as allowing the user to scrub to a position in the track.

21. Player Bar Part 1

Subscribers only

We have a player but there's currently no way to bring it back up after dismissing it. In this episode we'll design a persistent player bar that will control the player and will be allowed to live outside its view controller.

22. Player Bar Part 2

Subscribers only

We take our player bar and install it into a custom tab bar. To do this we have to create a custom tab bar controller and tab bar subclass and mix it with just a little bit of questionable UIKit hackery to get it to layout how we want. We'll talk about the tradeoffs for different approaches as well as see some useful debugging tips when a button isn't responding to taps.

23. My Podcasts Screen

Subscribers only

We refactor out some common logic to show a My Podcasts screen with all of the subscribed podcasts. We fetch the subscriptions using Core Data and listen for changes to subscriptions using our new Typed Notification system.

24. Setting up Core Data for Episodes

Subscribers only

In preparation for us to have a playlist of episodes ready to play in the app, we need to save the episodes to our Core Data store. In this episode we create the Episode model and associated class.

25. Refactor Core Data Context Handling

Subscribers only

Our current SubscriptionStore is too tied to the main core data context. In this episode we'll split this behavior on to a new type that will manage persistence for us, as well as implement a solution to solve the problem of core data being initialized asynchronously. We want to delay our app's UI until we have a context we can use.

26. Importing Episodes from a Feed

Subscribers only

We finish off our operation to import all the episodes given a podcast id and save into the core data store. We also implement a FeedImporter class that listens for new subscriptions in order to kick off the import when a user subscribes.

27. Updating Feeds in the Background

Subscribers only

In this episode we update all of the episodes in the background when the application is launched. We leverage Operations to do this work and set the qualityOfService to prefer foreground work that the user is actively requesting.

28. Playlist Screen

Subscribers only

In this episode we create the UI for our playlist screen, showing episodes from each of the subscribed podcasts. On this screen we combine NSFetchedResultsController with UITableViewDiffableDatasource so that our playlist screen can react to changes to the underlying data and reload as necessary. We do this using the automaticallyMergesChangesFromParent on our NSManagedObjectContext.

29. Tracking Playback Progress

Subscribers only

To wrap up this series, we add a new model to track and persist the progress of playing episodes. We also restore the player and playback position when coming back from a cold launch.