I just wanted to start out by saying that this is an abridged version of my original published version from December 15, 2023 that you can find on my website here.
When moving my apps over from CoreData
to SwiftData
I came across a problem where I wasn't able to filter my query by another entity within its predicate. Whenever I did and tried to build the project it kept compiling and compiling and would eventually fail so the time wasted waiting while trying to solve the issue was another aggravation on top of it all.
To demonstrate the problem I took the iTour example project from Hacking with Swift and altered it a bit to showcase my problem and, eventually, the solution.
In his app there are two main data models. You have destinations you can visit and each one has a list of sights you can see at that destination. So for example if you were to visit Alberta (the destination) you could visit many sights while there like: Banff, Lake Louise, Royal Tyrrell Museum, and West Edmonton Mall. While a Destination
can include multiple Sight
s each Sight
can only belong to one Destination
. His example didn't show my issue but I altered it to include a list of Sight
s that needed to be filtered by the id
of a Destination
thus recreating my problem.
The problem, once solved, was very simple. I was filtering the Sight
data thus I could only filter by the data model Sight
and no other ones. My problem came when I introduced the Destination
. To get around this I took the persistentModelID
from the Destination
before entering into the Predicate
to filter by. That worked!
The working code, in case you want to use it towards your solution, is:
init(sort: [SortDescriptor<Sight>], searchString: String, destination: Destination?) {
// Make a point of grabbing
if let thisID = destination?.persistentModelID {
_sights = Query(filter: #Predicate<Sight> {
if searchString.isEmpty {
return $0.destination?.persistentModelID == thisID
} else {
return $0.destination?.persistentModelID == thisID && $0.name.localizedStandardContains(searchString)
}
}, sort: sort)
} else {
// if id is nil than I don't want ANYTHING that said you could instead return $0.name.localizedStandardContains(searchString)
_sights = Query(filter: #Predicate<Sight> { currSight in
return false
}, sort: sort)
}
}
And with that the issue was solved! If you want more information about the problem, the example, the building issues, or the solution itself you can check out my SimplyKyra website where I published the longer and original version of this post back in December of 2023.
Hope you have a great day!
Top comments (1)
Very useful post!