Episode #416

Updating Feeds in the Background

Series: Making a Podcast App From Scratch

10 minutes
Published on November 7, 2019

This video is only available to subscribers. Get access to this video and 571 others.

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.

Background Update of Subscribed Feeds

As the user launches the application, we'll start by importing the new episodes of the subscribed feeds. We'll use a qualityOfService of .background.

private var priorityQueue: OperationQueue = {
    let q = OperationQueue()
    q.maxConcurrentOperationCount = 2
    q.qualityOfService = .userInitiated
    return q

private var backgroundQueue: OperationQueue = {
    let q = OperationQueue()
    q.maxConcurrentOperationCount = 2
    q.qualityOfService = .background
    return q

Updating the Podcast

As we fetch the feeds and import new episodes, we'll update the podcast by adding these episodes. We'll make sure this operation runs in the background and simultaneously logs the details of the subscribed podcast.

func updatePodcasts() {
    backgroundQueue.addOperation {
        let context = PersistenceManager.shared.newBackgroundContext()
        let subscriptionStore = SubscriptionStore(context: context)
        do {
            let subs = try subscriptionStore.fetchSubscriptions()
            for sub in subs {
                guard let podcast = sub.podcast else { continue }
                guard let id = podcast.id else { continue }
                print("Queueing operation to update subscribed podcast: \(podcast.title ?? "?")")
                let updateOperation = ImportEpisodesOperation(podcastId: id)
        } catch {
            print("Error fetching subscriptions for background update. \(error)")

As the application launches, we'll update the podcast on a background queue.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    window = UIWindow()

    Theme.apply(to: window!)

    window?.rootViewController = UIViewController()

    PersistenceManager.shared.initializeModel(then: {

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        self.window?.rootViewController = storyboard.instantiateInitialViewController()            

    return true

Note that we've also bumped the minimum version of the app to iOS 13.

This episode uses Xcode 11.1, Swift 5.1.