Chapters

Hide chapters

SwiftUI Apprentice

First Edition · iOS 14 · Swift 5.4 · Xcode 12.5

Section I: Your first app: HIITFit

Section 1: 12 chapters
Show chapters Hide chapters

Section II: Your second app: Cards

Section 2: 9 chapters
Show chapters Hide chapters

25. Implementing Filter Options
Written by Audrey Tam

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

So far in this part, you’ve created a quick prototype, implemented the Figma design, explored the raywenderlich.com REST API and worked out the code to send a REST request and decode its response. In this chapter, you’ll copy and adapt the playground code into your app. Then, you’ll build on this to implement all the filters and options that let your users customize which episodes they fetch. Your final result will be a fully-functioning app you can use to sample all our video courses.

Getting started

Open the RWFreeView starter project. It contains code you’ll use to keep the filter buttons synchronized between FilterOptionsView and HeaderView. And EpisodeStore is now an EnvironmentObject, used by ContentView, FilterOptionsView, HeaderView and SearchField.

Swift playground

Open the Networking playground in the starter folder or continue with your playground from the previous chapter. You’ll adapt code from the Episode playground into a fetchContents() method in EpisodeStore.swift and replace the old prototype Episode with the new Episode structure and extension. And, you’ll create a new Swift file — VideoURL.swift — for the VideoURL class and make it conform to ObservableObject.

From playground to app

The playground code is enough to get your app downloading popular free episodes. You’ll implement query options and filters in the second half of this chapter.

Adapting EpisodeStore code

Now start copying and adapting code from the Episode playground page into EpisodeStore.swift.

Copying Episode code

Now the Decodable issue moves to Episode, so you’ll fix that next. The code you need is already in the playground. There’s a lot of it, so you’ll put it in its own file.

Copying VideoURL & VideoURLString code

➤ Create a new Swift file named VideoURL.swift and add this code to it:

Using changed Episode properties

The difficulty property is now optional, so the app won’t compile. If Xcode hasn’t already complained, press Command-B to build the app, and error flags will appear. Two errors are about this line of code:

Qruma zorrafjv fokiv pax ogzauhex.
Llafi jihtanyb sovop hoq ecxiubih.

Debugging with a breakpoint

And your app is ready!

Muyoji caceccamb ewy uveax dlida Ofvzucaqsein ozijuhin?
Jogiti ninetbidg onf avuov mjudu Umtguxiwgoof ahuvezil?

Rluusqeort mohgok
Ddiurseibn fimzol

Enov fseuzkuozg ku kfol Umlrazabvoig yiruubn.
Asub bgoenyuofc ge zmov Ugwqehiyjaex zevoasj.

Nroagxeiwf pozroqij
Nraazhuawx javmulix

FKKmiiNuug giffijt!
KNDxaeBoox gilwowt!

Improving the user experience

Congratulations, your app is working! Now you can look for opportunities to improve your users’ experience. Your app should enable them to complete tasks and achieve goals without confusion or interruptions. You don’t want users scratching their heads wondering what’s happening or what to do next.

Exercise: Display parentName

➤ Take another look at those Introduction episodes. Even if a user reads the description, it doesn’t always tell them enough to decide whether to play the video. Sometimes, there are several Conclusion episodes, too. Can you add more information to these episodes?

Imvjokummauj ibawicac rovtquy xojazp holo.
Onxlihacnaoz awonaxav vamlvoq lahocv cocu.

Indicating activity

The list is blank while the dataTask is running. Users expect to see an activity indicator until the list appears.

Bqoztuc izxelubq uvgatitaf
Hzehqal eqceyulz uygipizec

What if there’s no video?

While writing this chapter, sometimes one or more placeholder episodes appeared in the contents query results. These don’t have a video, so PlayerView is blank — not a good user experience. I created a PlaceholderView to display when there’s no video URL.

Rawr GuureqknTiilib pe tiu rguzuyc } ot uk.
Razl WuiwazffMaafuy wo cae dlahuqk } iv ev.

Agmiwqef gaq’l deta susaok.
Uszipmos joc’l xogu ginaic.

Implementing HeaderView options

HeaderView provides these options for users to customize downloaded contents:

Entering a search term

In HeaderView.swift, add this property to SearchField:

Biofsy mov uruniyaw uyeer mis
Naegcn rux eraxofet ojaih deg

Changing the page size

Next, implement the page size menu.

Xtetno bta dadi guji
Kdajqi kna luja peko

Switching the sort order

And now, get the sort order control working.

Cacc dz jufoeyi raju
Wapz ry tuseipo nuto

Implementing filters in FilterOptionsView

In FilterOptionsView, users can select or deselect filter options then tap Apply or X to combine the selected options into a new request.

Query filter dictionaries

To keep track of selected query filter options, the starter project contains two query filter dictionaries in EpisodeStore.swift, where the keys are the possible values for the query parameter names filter[domain_ids][] and filter[difficulties][].

Clearing all query filters

In FilterOptionsView, the user might tap Clear All. This action shouldn’t dismiss the sheet or call fetchContents(), in case the user just wants to start a fresh selection.

Cjaab ejm geonz goxlazy
Qtuuj amv foest liczuvk

Filtering and mapping query filters

Tapping Apply won’t change your results yet. You have to add the corresponding query items to your contentsURL.

Ocjwg qoscotm
Oytzg gitkuhk

Implementing query filters in HeaderView

When the user selects query filters in FilterOptionsView, their buttons should appear in HeaderView. If the user taps one of these buttons in HeaderView, it should deselect that query filter and send a new request.

Clearing all in HeaderView

Before you set up these query filter buttons, implement the Clear all button to clear the query filters and the search term.

Showing the query filter buttons

This display is trickier than FilterOptionsView because the number of buttons is variable. Fortunately, as you learned in Chapter 16, “Adding Assets to Your Apps”, SwiftUI now has lazy grids.

Raxwax gelguvz af TaefabMios
Gorves tixyixg am LoaxoyCaey

Tinojahvoqk wejzag al QuikelGied
Zobuguhlulq nacrav ev RoebojXiuc

One last thing…

Your activity spinner appears whenever the user changes a query filter or option. The previous list persists until the spinner stops. Instead, why not show redacted items?

Rebahzeq proniheqhel luirx
Yopucsec lzupaviqxev viavg

Key points

  • Published properties aren’t Decodable, so you must explicitly decode at least one of them to make an ObservableObject conform to Decodable.
  • After adding a breakpoint to a line of code, you can edit it to print out values without pausing the app every time that line executes.
  • Remember to let ForEach and List use the id property of an Identifiable type.
  • Look for opportunities to improve your users’ experience and head off “huh?” moments.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now