SwiftData #Predicate performs $0.string1 == string2 as case sensitive. Searching for Taylor Swift returns results, but not for taylor swift.
In Core Data we did this with ==[c]
How do we do this in SwiftData?
SwiftData #Predicate performs $0.string1 == string2 as case sensitive. Searching for Taylor Swift returns results, but not for taylor swift.
In Core Data we did this with ==[c]
How do we do this in SwiftData?
Same problem. I couldn't find any solution. The macro uses PredicateExpressions enumerations to build the predicate. The enumeration includes a lot of methods but none seems to work for case insensitive searches. I hope they fix this soon or SwiftData becomes completely useless for most cases.
I've played around with this, trying a lot of solutions, but I might have found a way to do case insensitive compare. In the SwiftData SampleTrips sample project I changed
let filteredList = try? trip.bucketList.filter(#Predicate { item in
item.title.contains(searchText) && tripName == item.trip?.name
})
to:
let filteredList = try? trip.bucketList.filter(#Predicate { item in
return item.title.localizedLowercase.contains(searchText.localizedLowercase) && tripName == item.trip?.name
})
This seemed to work. It seems the macro has support for localizedLowercase
but not for lowerCased()
Hope that helps. I'm a lot more excited about SwiftData now.
I followed your suggestion:
musicAlbumPredicate = #Predicate<MusicAlbum> {
$0.artistName.localizedLowercase.contains(searchQuery.localizedLowercase)
}
It produced the following error messages:
SwiftData/DataUtilities.swift:93: Fatal error: Couldn't find \MusicAlbum.artistName.localizedLowercase on MusicAlbum with fields [("artistName", \MusicAlbum.artistName, nil, nil), ("albumName", \MusicAlbum.albumName, nil, nil), ("songName", \MusicAlbum.songName, nil, nil), ("genre", \MusicAlbum.genre, nil, nil), ("rating", \MusicAlbum.rating, nil, nil), ("releaseDate", \MusicAlbum.releaseDate, nil, nil), ("coverPhotoFullFilename", \MusicAlbum.coverPhotoFullFilename, nil, nil)]
Just use the localizedStandardContains(_:)
function in your predicate.
let predicate = #Predicate<Band> { $0.name.localizedStandardContains(userInput) }
This is the most appropriate method for doing user-level string searches, similar to how searches are done generally in the system. The search is locale-aware, case and diacritic insensitive. The exact list of search options applied may change over time.
https://developer.apple.com/documentation/swift/stringprotocol/localizedstandardcontains(_:)
I'm sorry, but this isn't right. localizedStandardContains(_:)
provides CONTAINS semantics, not EQUALS semantics. The original poster (and I) want a case-insensitive test for equality. Using localizedStandardCompare(_:) == .orderedSame
is not supported by the current (Xcode 15.0 beta 7) version of SwiftData, and the alternative suggested by Xcode's error messages (localizedCompare(_:))
is case-sensitive.
The only thing I can think of at this point (not tested, by the way) is
$0. attribute.localizedStandardContains(str) && str.localizedStandardContains($0.attribute)
which is ridiculous. FB13051739
SwiftData is not ready for prime time until this gets addressed!
Predicates only provide support for caseInsensitiveCompare(_:)
when making case-insensitive string comparisons. This function returns a ComparisonResult
, which has three cases: orderedAscending
, orderedSame
, and orderedDescending
.
To create a predicate that does a case-insensitive string comparison, you'll first need to create a constant defining the expected return value. This is because referring to an enum case using a keypath (e.g. ComparisonResult.orderedSame
) is not supported in predicates.
let orderedSame = ComparisonResult.orderedSame
let predicate = #Predicate<Person> { person in
person.name.caseInsensitiveCompare(name) == orderedSame
}