In Swift Data I have a basic model
@Model class MovieSD {
@Attribute(.unique) var title: String
var genre: [String] = [String]()
init(title: String) {
self.title = title
}
}
I am trying to create predicates when fetching the data. Creating a predicate to search by title works as expected
let movieTitle = #Predicate<MovieSD> { movie in
movie.title.contains("filterstring")
}
But when attempting to do the same for the String array
let movieGenre = #Predicate<MovieSD> { movie in
movie.genre.contains("filterstring")
}
Results in a crash with EXC_BAD_ACCESS
Similar approaches produce a different error and point to the likely issue.
let movieGenre2 = #Predicate<MovieSD> { movie in
if movie.genre.contains(where: { $0 == "filterstring" }) {
return true
} else {
return false
}
}
Results in a crash with the error:
error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x281a96840> , Can't have a non-relationship collection element in a subquerySUBQUERY(genre, $$_local_1, $$_local_1 == "SciFi") with userInfo of (null)
or alternatively largely the same error for:
let movieGenre3 = #Predicate<MovieSD> { movie in
movie.genre.filter { genre in
return genre == "filterstring"
}.count > 0
}
It seems that Swift Predicate should be able to make condition statements that would rely on SUBQUERY with NSPredicate. But in this case it doesn't seem too be working.
Naturally, I can use similar to the above to filter the array that is returned. But this seems inefficient. And it seems it should be possible to filter. Also, I want to avoid approaches that make the genres array into a @model Genre class.
Any help showing how to filter a String array with a predicate with Swift Data would be appreciated.
If it suits your application you could store the genre in a different table and query on that.
@Model class Genre {
@Attribute(.unique) var name: String
init(name: String) {
self.name = name
}
}
@Model class MovieSD {
@Attribute(.unique) var title: String
var genre = [Genre]()
init(title: String) {
self.title = title
}
}
This article can help explain why this happens.
if you use collections of value types, e.g. [String], SwiftData will save that directly inside a single property too. Right now it’s encoded as binary property list data, which means you can’t use the contents of your array in a predicate.