Reputation: 77
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
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:
Upvotes: 1
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.
true
, that means keep the elementfalse
, then remove the elementIn 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