Поддерживает ли макрос #Predicate в Foundation/SwiftData поиск без учета регистра?
Я тестирую новую платформу SwifData и работаю с новым макросом #Predicate и понял, что он не поддерживает поиск без учета регистра. Макрос не работает с методом lowcased() или свойством localizedLowercase, поэтому, похоже, нет способа создать предикат, нечувствительный к регистру, как мы привыкли делать с NSPredicate и атрибутом [c].
var predicate = #Predicate<Book> {
$0.title.localized().contains(search) }
Ошибка: функция нижнего регистра() не поддерживается в этом предикате (из макроса «Предикат»).
Интересно, есть ли какой-нибудь обходной путь? Спасибо
2 ответа
НовыйPredicate
макрос очень хорошо работает сlocalizedStandardContains(_:)
функция.
С сайта документации разработчиков Apple :
Это наиболее подходящий метод для поиска строк на уровне пользователя, аналогичный тому, как поиск обычно выполняется в системе. Поиск осуществляется с учетом локали, нечувствителен к регистру и диакритическим знакам. Точный список примененных параметров поиска может со временем измениться.
Использование:
let userInput = "foo bar"
let predicate = #Predicate<Book> { $0.title.localizedStandardContains(userInput) }
ОБНОВЛЕНИЕ Как отметила Микико Джейн, это работает только в предикате фильтра для массива, а не в@Query
напрямую.
Я попытался использовать@Transient
поле, чтобы на лету сделать его строчными буквами
@Transient
var nameNormalized: String {
name.lowercased()
}
Предикат не смог увидеть свойство transient, поскольку я предполагаю, что он ищет только те объекты, которые сохранились в базе данных.
Я полагаю, что единственное решение на данный момент — создать поле, которое обновляется всякий раз, когда обновляется первое поле. Это слишком много накладных расходов и шаблонов, чтобы просто иметь правильную функциональность поиска. Кажется, это явно противоречит целям SwiftData.
Оригинальный ответ
Я поигрался с этим, перепробовав множество решений, но, возможно, нашел способ выполнить сравнение без учета регистра. В примере проекта SwiftData SampleTrips я изменил
let filteredList = try? trip.bucketList.filter(#Predicate { item in
item.title.contains(searchText) && tripName == item.trip?.name
})
к:
let filteredList = try? trip.bucketList.filter(#Predicate { item in
return item.title.localizedLowercase.contains(searchText.localizedLowercase) && tripName == item.trip?.name
})
Кажется, это сработало. Кажется, макрос поддерживаетlocalizedLowercase
но не дляlowerCased()