NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

Dynamically filtering a SwiftUI List

Paul Hudson    @twostraws   

SwiftUI’s List view likes to work with arrays of objects that conform to the Identifiable protocol, or at least can provide some sort of id parameter that is guaranteed to be unique. However, there’s no reason these need to be stored properties of a view, and in fact if we send in a computed property then we’re able to adjust our filtering on demand.

In our app, we have three instances of ProspectsView that vary only according to the FilterType property that gets passed in from our tab view. We’re already using that to set the title of each view, but we can also use it to set the contents for a List.

The easiest way to do this is using Swift’s filter() method. This runs every element in a sequence through a test you provide as a closure, and any elements that return true from the test are sent back as part of a new array. Our ProspectsView already has a prospects property being passed in with an array of people inside it, so we can either return all people, all contacted people, or all uncontacted people.

Add this property to ProspectsView below the previous two:

var filteredProspects: [Prospect] {
    switch filter {
    case .none:
        return prospects.people
    case .contacted:
        return prospects.people.filter { $0.isContacted }
    case .uncontacted:
        return prospects.people.filter { !$0.isContacted }
    }
}

When filter() runs, it passes every element in the people array through our test. So, $0.isContacted means “does the current element have its isContacted property set to true?” All items in the array that pass that test – that have isContacted set to true – will be added to a new array and sent back from filteredResults. And when we use !$0.isContacted we get the opposite: only prospects that haven’t been contacted get included.

With that computed property in place, we can now create a List to loop over that array. This will show both the title and email address for each prospect using a VStack, and we’ll also use a ForEach so we can add deleting later on.

Replace the existing text view in ProspectsView with this:

List {
    ForEach(filteredProspects) { prospect in
        VStack(alignment: .leading) {
            Text(prospect.name)
                .font(.headline)
            Text(prospect.emailAddress)
                .foregroundColor(.secondary)
        }
    }
}

If you run the app again you’ll see things are starting to look much better.

Before we move on, I want you to think about this: now that we’re using a computed property, how does SwiftUI know to refresh the view when the property changed? The answer is actually quite simple: it doesn’t.

When we added an @EnvironmentObject property to ProspectsView, we also asked SwiftUI to reinvoke the body property whenever that property changes. So, whenever we insert a new person into the people array its @Published property wrapper will announce the update to all views that are watching it, and SwiftUI will reinvoke the body property of ProspectsView. That in turn will calculate our computed property again, so the List will change.

I love the way SwiftUI transparently takes on so much work for us here, which means we can focus on how we filter and present our data rather than how to connect up all the pipes to make sure things are kept up to date.

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until October 1st.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.6/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.