JamesH
JamesH

Reputation: 77

Filter Logic in SwiftUI - Apple Tutorial

I am working the Landmarks SwiftUI tutorial https://developer.apple.com/tutorials/swiftui/handling-user-input. I am stumped on the use of the logical operators in

landmarks.filter { landmark in
            (!showFavoritesOnly || landmark.isFavorite)
        }

I am trying to understand how this logic works in returning the filteredLandmarks. I'm pretty sure the ! operator inverts the showFavoritesOnly operand and the || operator on landmark.isFavorite makes the statement true if either side is true in the closure but for some reason this what is supposed to happen as far as what is returned escapes me at the moment. If anyone can clarify I'd be very appreciative.

Here's the file for context:

 import SwiftUI
    
    struct LandmarkList: View {
        @State private var showFavoritesOnly = false
        
        var filteredLandmarks: [Landmark] {
            landmarks.filter { landmark in
                (!showFavoritesOnly || landmark.isFavorite)
            }
        }
        
        var body: some View {
            NavigationView {
                List(filteredLandmarks)
                    { landmark in
                    NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                        LandmarkRow(landmark: landmark)
                    }
                }
                .navigationTitle("Landmarks")
            }
        }
    }
    
    struct LandmarkList_Previews: PreviewProvider {
        static var previews: some View {
                LandmarkList()
        }
    }

Upvotes: 2

Views: 662

Answers (2)

DantonC
DantonC

Reputation: 11

!showFavoritesOnly is the same as saying if (showFavoritesOnly == false) return true

So, when evaluating for the filtered list: If !showFavoritesOnly, it has no need to evaluate the rest of the statement as a 'true' is returned, and the element is placed in the list to be shown (ie an unfiltered list of all elements in this case, as every element will evaluate to showFavoritesOnly == false).

However, once showFavoritesOnly becomes true, the computer then evaluates the next half of the statement.

I made a flowchart which helps me visualise this concept:

Flowchart

Upvotes: 1

aheze
aheze

Reputation: 30426

I'm pretty sure the ! operator inverts the showFavoritesOnly operand and the || operator on landmark.isFavorite makes the statement true if either side is true

You are completely right.

but for some reason this what is supposed to happen as far as what is returned escapes me at the moment.

The filter(_:) method lets you filter an array (remove elements that don't satisfy a condition).

It takes in a closure, isIncluded. This closure is called once for each element in the array, with the current element passed into the parameter:

               /// ↓ the current element in the array
landmarks.filter { landmark in }

This closure must return a Bool, which represents if the element should be kept.

  • So if it returns true, that means keep the element
  • If false, then remove the element

In your implementation, you're keeping the elements whose showFavoritesOnly is false OR isFavorite is true.

landmarks.filter { landmark in
    (!showFavoritesOnly || landmark.isFavorite) /// return the Bool
}

Maybe you're confused as to why there's not a return statement...

landmarks.filter { landmark in
    return (!showFavoritesOnly || landmark.isFavorite)
}

The reason is because the return keyword is optional when you only have one expression. If you did something like:

landmarks.filter { landmark in
    let elementShouldBeKept = (!showFavoritesOnly || landmark.isFavorite)
    return elementShouldBeKept
}

... then you'd need the return.

Upvotes: 5

Related Questions