Перевод статьи
Эта страница содержит примеры использования NSPredicate, посмотрите здесь примеры использования Core Data. 🔋
Оглавление
База
Формат предиката и аргументы
Спецификатор формата строки
Основное сравнение
Составное сравнение
Сравнение без учета регистра
Техники
Повторное использование NSPredicate с замещающей переменной
Использование NSPredicate для фильтрации массива объектов
Примеры (собственность сущности…)
Входит в массив значений
Не входит в массив значений
Начинается с определенной строки
Содержит определенную строку
Заканчивается определенной строкой
Подстановочный знак соответствует строке
Регулярное выражение соответствует строке
База
Формат предиката и аргументы
Скажем для предиката, который выбирает человека с именем «Азриэль» и с 50 наличностью:
let fetchRequest = NSFetchRequest<Person>(entityName: "Person")
fetchRequest.predicate = NSPredicate(format: "name == %@ AND money == %i", "Asriel", 50)
формат «name == %@ AND money == %i»
%@ и %i являются спецификаторами формата, %@ заменяется объектом (например, строкой, датой и т. д.), тогда как %i заменяется целым числом.
Замена происходит, как показано ниже, в порядке слева направо:
%@ (описатель формата объекта) будет заменен на «Asriel», а %i (описатель целочисленного формата) будет заменен на 50. Asriel и 50 — это аргументы.
После подстановки предикат станет «name == ‘Asriel’ AND money = 50» , что означает, что NSPredicate найдет для Person имя Asriel и 50 money.
Но почему я не могу просто использовать «имя == ‘Азриэль’ И деньги = 50» вместо того, чтобы использовать спецификатор формата?
Да, конечно ты можешь! Для простого фильтра, который требует жестко заданного значения, я рекомендую использовать его. Замена спецификатора формата обычно используется для значения переменной, например:
// user input a name into textfield
var name = nameTextField.text!
// filter based on the name user has inputed
let fetchRequest = NSFetchRequest<Person>(entityName: "Person")
fetchRequest.predicate = NSPredicate(format: "name == %@", name)
Спецификатор формата строки
Вы можете проверить полный список в официальной документации Apple. %@ используется для таких объектов, как String, Date, Array и т. д. %K используется для Keypath (свойство сущности).
let integerPredicate = NSPredicate(format: "money == %i", 10000)
let doublePredicate = NSPredicate(format: "perimeter > %f", 3.14159)
let stringPredicate = NSPredicate(format: "name == %@", "Asriel")
// eg: find loans that are overdue
let datePredicate = NSPredicate(format: "due_date < %@", Date())
// the above can be replaced with this
let keyPathDatePredicate = NSPredicate(format: "%K < %@", "due_date", Date())
Основное сравнение
Основной символ сравнения, такой как ==, > , < и т. д.
let equalPredicate = NSPredicate(format: "name == %@", "Steve Jobs")
let notEqualPredicate = NSPredicate(format: "name != %@", "Steve Jobs")
let greaterPredicate = NSPredicate(format: "money > %i", 10000)
let greaterOrEqualPredicate = NSPredicate(format: "money >= %i", 10000)
let lesserPredicate = NSPredicate(format: "money < %i", 10000)
let lesserOrEqualPredicate = NSPredicate(format: "money <= %i", 10000)
Составное сравнение
Соедините два или более условий вместе с помощью OR, AND.
// Retrieve records where all conditions are met
let andPredicate = NSPredicate(format: "name == %@ AND money >= %i", "Steve Jobs", 10000)
// Retrieve records as long as one of the condition is met
let orPredicate = NSPredicate(format: "name == %@ OR money >= %i", "Steve Jobs", 10000)
Сравнение без учета регистра
Для сравнения без учета регистра поставьте [c] после символа сравнения.
// Works for "jobs", "Jobs", "jObS"
let caseInsensitivePredicate = NSPredicate(format: "name ==[c] %@", "Jobs")
Техники
Повторное использование NSPredicate с замещающей переменной
Поскольку для анализа строки формата NSPredicate приложению требуется относительно много времени, мы должны попытаться сократить создание нескольких NSPredicate и максимально повторно использовать похожие NSPredicate. Мы можем использовать значение переменной в NSPredicate, обозначенное знаком $, и подставить его значение, вызвав метод withSubstitutionVariables.
// Persons' name : ["Asriel", "Asgore", "Toriel", "Frisk", "Flowey"]
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<Person>(entityName: "Person")
let reusablePredicate = NSPredicate(format: "name BEGINSWITH $startingName")
// replace $startingName with 'As'
fetchRequest.predicate = reusablePredicate.withSubstitutionVariables(["startingName" : "As"])
do {
people = try context.fetch(fetchRequest)
// ["Asriel", "Asgore"]
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
// reuse the predicate with a different starting name
// replace $startingName with 'F'
fetchRequest.predicate = reusablePredicate.withSubstitutionVariables(["startingName" : "F"])
do {
people += try context.fetch(fetchRequest)
// ["Asriel", "Asgore", "Flowey", "Frisk"]
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
Вы можете использовать несколько переменных, таких как имя BEGINSWITH $startingName AND money > $amount , а затем вызвать withSubstitutionVariables([«startingName» : «As», «amount»: 50]).
Использование NSPredicate для фильтрации массива объектов
Помимо Core Data, мы также можем использовать NSPredicate для фильтрации массива объектов. SELF в строке формата означает каждый отдельный элемент в массиве.
let names = ["Kim Kardashian", "Kim Jong Un", "Jimmy Kimmel", "Ken"]
var filteredNames : [String] = []
// SELF means each element in the array
let containPredicate = NSPredicate(format: "SELF CONTAINS %@", "Kim")
filteredNames = names.filter({ name in
// the evaluate function will return true if the element satisfy the predicate,
// otherwise false
containPredicate.evaluate(with: name)
})
print("\(filteredNames)")
// ["Kim Kardashian", "Kim Jong Un", "Jimmy Kimmel"]
Примеры (собственность сущности…)
Входит в массив значений
let wantedItemIDs = [1, 2, 3, 5, 8, 13, 21]
// Retrieve record with item_id which is inside the wantedItemIDs array
let inclusivePredicate = NSPredicate(format: "item_id IN %@", wantedItemIDs)
Не входит в массив значений
let unwantedItemIDs = [1, 2, 3, 5, 8, 13, 21]
// Retrieve record with item_id which is not inside the unwantedItemIDs array
let exclusivePredicate = NSPredicate(format: "NOT (item_id IN %@)", unwantedItemIDs)
Начинается с определенной строки
// Works for "Steven Paul Jobs", "Logan Paul"
let containPredicate = NSPredicate(format: "name CONTAINS %@", "Paul")
// Works for "Shop1", "shopping", "my shop", "bishop"
let containCaseInsensitivePredicate = NSPredicate(format: "name CONTAINS[c] %@", "shop")
// the [c] means case insensitive match
Содержит определенную строку
// Works for "Steven Paul Jobs", "Logan Paul"
let containPredicate = NSPredicate(format: "name CONTAINS %@", "Paul")
// Works for "Shop1", "shopping", "my shop", "bishop"
let containCaseInsensitivePredicate = NSPredicate(format: "name CONTAINS[c] %@", "shop")
// the [c] means case insensitive match
Заканчивается определенной строкой
// Works for "Steve Jobs", "Lisa Jobs"
let endPredicate = NSPredicate(format: "name ENDSWITH %@", "Jobs")
// Works for "mundane jobs", "Steve Jobs"
let endCaseInsensitivePredicate = NSPredicate(format: "name ENDSWITH[c] %@", "jobs")
// the [c] means case insensitive match
Подстановочный знак соответствует строке
LIKE используется для сопоставления с подстановочными знаками.
Подстановочный знак используется для соответствия определенному шаблону строки, например: для соответствия img1.png , img10.png и img100.png мы можем использовать имя файла LIKE ‘img*.png’. * означает, что принимается ноль или более символов между img и .png.
let filenameArr = ["img.png", "img1.png", "img2.png", "img10.png", "img100.png", "img200.txt", "img300.csv"]
let pngPredicate = NSPredicate(format: "SELF LIKE %@", "img*.png")
let imageArr = filenameArr.filter(){ filename in
pngPredicate.evaluate(with: filename)
}
print(imageArr)
// ["img.png", "img1.png", "img2.png", "img10.png", "img100.png"]
Чтобы соответствовать только одному символу, мы можем использовать ? , например: имя файла LIKE ‘img?.png’ будет соответствовать img1.png, но не img10.png, поскольку принимает только один символ между img и .png.
let filenameArr = ["img.png", "img1.png", "img2.png", "img10.png", "img100.png", "img200.txt", "img300.csv"]
let singleCharPngPredicate = NSPredicate(format: "SELF LIKE %@", "img?.png")
let imageArr2 = filenameArr.filter(){ filename in
singleCharPngPredicate.evaluate(with: filename)
}
print(imageArr2)
// ["img1.png", "img2.png"]
Регулярное выражение соответствует строке
MATCHES используется для сопоставления с регулярным выражением.
Регулярное выражение используется для сопоставления сложных строковых шаблонов. Swift использует формат регулярных выражений ICU. Для изучения регулярных выражений я рекомендую это руководство.
Например: имя файла СОВПАДАЕТ ‘img\\d{1,3}\\.png‘ будет соответствовать имени файла с 1-3 цифрами между img и .png, например img1.png, img10.png и img100.png, но не img1000.png. Двойная обратная косая черта используется для экранирования символа обратной косой черты \ .
let filenameArr = ["img.png", "img1.png", "imgABC.png", "img10.png", "img100.png", "img9000.png", "img12345.png"]
// matches filename that has 1-3 digits between 'img' and '.png'
let regexPredicate = NSPredicate(format: "SELF MATCHES %@", "img\\d{1,3}\\.png")
let filteredArr = filenameArr.filter(){ filename in
regexPredicate.evaluate(with: filename)
}
print(filteredArr)
// ["img1.png", "img10.png", "img100.png"]