Создание предикатов

Существует три способа создать предикат в Какао: использование строки формата, непосредственно в коде, и из шаблона предиката.

Создание предиката Используя строку формата

Можно использовать NSPredicate методы класса формы predicateWithFormat… создать предикат непосредственно из строки. Вы определяете предикат как строку, дополнительно с помощью подстановки переменных. Во время выполнения, подстановку переменных — если кто-либо — выполняется, и получившая строка анализируется для создания соответствующего предиката и объектов выражения. Следующий пример создает составной предикат с двумя предикатами сравнения.

NSPredicate *predicate = [NSPredicate
    predicateWithFormat:@"(lastName like[cd] %@) AND (birthday > %@)",
            lastNameSearchString, birthdaySearchDate];

(В примере, like[cd] измененный «как» оператор, который нечувствителен к регистру и нечувствителен к диакритическому знаку.) Для полного описания строкового синтаксиса и списка всех доступных операторов, посмотрите Синтаксис Строки формата Предиката.

Строковый синтаксический анализатор предиката является пробелом, нечувствительным, нечувствительным к регистру относительно ключевых слов, и поддерживает вложенные вводные выражения. Это также поддерживает printf- разработайте спецификаторы формата (как %x и %@) — посмотрите Строковые Объекты Форматирования. Переменные обозначены с a $ (например, $VARIABLE_NAME) — дополнительную информацию см. в Предикатах Создания Используя Шаблоны Предиката.

Синтаксический анализатор не выполняет семантической проверки типа. Это прилагает усилие лучшего предположения для создания подходящих выражений, но — особенно в случае переменных замены — возможно, что будет сгенерирована ошибка периода выполнения.

Этот подход обычно лучше всего используется для предопределенных условий запроса, несмотря на то, что подстановка переменных допускает значительную гибкость. Недостаток этого метода - то, что необходимо заботиться, чтобы избежать вводить ошибки в строку — Вы не обнаружите ошибки до времени выполнения.

Строковые константы, переменные и подстановочные знаки

Строковые константы должны быть заключены в кавычки в выражении — одинарные и двойные кавычки оба приемлемы, но должны быть соединены соответственно (т.е. двойная кавычка (") не соответствует одинарную кавычку (')). Если Вы используете использование подстановки переменных %@ (такой как firstName like %@), кавычки добавляются для Вас автоматически. При использовании строковых констант в строке формата необходимо заключить им в кавычки сами, как в следующем примере.

NSPredicate *predicate = [NSPredicate
    predicateWithFormat:@"lastName like[c] \"S*\""];

Необходимо принять автоматическую котировку во внимание при использовании подстановочных знаков — необходимо добавить подстановочные знаки к переменной до замены, как показано в следующем примере.

NSString *prefix = @"prefix";
NSString *suffix = @"suffix";
NSPredicate *predicate = [NSPredicate
    predicateWithFormat:@"SELF like[c] %@",
    [[prefix stringByAppendingString:@"*"] stringByAppendingString:suffix]];
BOOL ok = [predicate evaluateWithObject:@"prefixxxxxxsuffix"];

В этом примере подстановка переменных производит строку предиката SELF LIKE[c] "prefix*suffix", и значение ok YES. Следующий фрагмент, в отличие от этого, приводит к строке предиката SELF LIKE[c] "prefix" * "suffix", и оценка предиката приводит к ошибке периода выполнения:

predicate = [NSPredicate
    predicateWithFormat:@"SELF like[c] %@*%@", prefix, suffix];
ok = [predicate evaluateWithObject:@"prefixxxxxxsuffix"];

Наконец, следующий фрагмент приводит к ошибке анализа во время выполнения (Unable to parse the format string "SELF like[c] %@*").

predicate = [NSPredicate
    predicateWithFormat:@"SELF like[c] %@*", prefix];

Необходимо также отметить различие между подстановкой переменных в строке формата и переменными выражениями. Следующий фрагмент кода создает предикат с правой стороной, которая является переменным выражением.

predicate = [NSPredicate
    predicateWithFormat:@"lastName like[c] $LAST_NAME"];

Для больше о переменных выражениях, посмотрите, что Предикаты Создания Используют Шаблоны Предиката.

Булевы значения

Вы указываете и тестируете на равенство булевых значений, как проиллюстрировано в следующих примерах:

NSPredicate *newPredicate =
    [NSPredicate predicateWithFormat:@"anAttribute == %@", [NSNumber numberWithBool:aBool]];
NSPredicate *testForTrue =
    [NSPredicate predicateWithFormat:@"anAttribute == YES"];

Имена динамического свойства

Поскольку строковые переменные окружаются кавычками, когда ими заменяют в использование строки формата %@, Вы не можете использовать %@ указать имя динамического свойства — как проиллюстрировано в следующем примере.

NSString *attributeName = @"firstName";
NSString *attributeValue = @"Adam";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ like %@",
        attributeName, attributeValue];

Строка формата предиката в этом случае оценивает к "firstName" like "Adam".

Если Вы хотите указать имя динамического свойства, Вы используете %K в строке формата, как показано в следующем фрагменте.

predicate = [NSPredicate predicateWithFormat:@"%K like %@",
        attributeName, attributeValue];

Строка формата предиката в этом случае оценивает к firstName like "Adam" (обратите внимание на то, что нет никаких кавычек вокруг firstName).

Создание предикатов непосредственно в коде

Можно создать предикат и экземпляры выражения непосредственно в коде. NSComparisonPredicate и NSCompoundPredicate обеспечьте удобные методы, позволяющие Вам легко создавать составной объект и предикаты сравнения соответственно. NSComparisonPredicate предоставляет многим операторам в пределах от простых тестов равенства к пользовательским функциям.

Следующий пример показывает, как создать предикат для представления (revenue >= 1000000) and (revenue < 100000000). Обратите внимание на то, что то же левое выражение стороны используется для обоих предикатов сравнения.

NSExpression *lhs = [NSExpression expressionForKeyPath:@"revenue"];
 
NSExpression *greaterThanRhs = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:1000000]];
NSPredicate *greaterThanPredicate = [NSComparisonPredicate
    predicateWithLeftExpression:lhs
    rightExpression:greaterThanRhs
    modifier:NSDirectPredicateModifier
    type:NSGreaterThanOrEqualToPredicateOperatorType
    options:0];
 
NSExpression *lessThanRhs = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:100000000]];
NSPredicate *lessThanPredicate = [NSComparisonPredicate
    predicateWithLeftExpression:lhs
    rightExpression:lessThanRhs
    modifier:NSDirectPredicateModifier
    type:NSLessThanPredicateOperatorType
    options:0];
 
NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
    @[greaterThanPredicate, lessThanPredicate]];

Недостаток этого метода должен быть сразу очевидным — Вам, вероятно, придется записать много кода. Преимущества состоят в том, что это менее подвержено написанию и другим типографским ошибкам, которые могут только быть обнаружены во время выполнения, и это может быть быстрее, чем в зависимости от строкового парсинга.

Когда создание предиката будет самостоятельно динамичным, такой как в разработчике предиката, этот метод, наиболее вероятно, будет полезен.

Создание предикатов Используя шаблоны предиката

Шаблоны предиката предлагают хороший компромисс между простым в использовании, но потенциально подверженным ошибкам форматом основанный на операция со строками метод и интенсивным кодом чистым подходом кодирования. Шаблон предиката является просто предикатом, включающим переменное выражение. (При использовании Базовой платформы Данных можно использовать средства проектирования XCode, чтобы добавить, что шаблоны предиката для выборки запрашивают к модели — посмотрите Модели Управляемого объекта.) Следующий пример использует строку формата для создания предиката с правой стороной, которая является переменным выражением.

NSPredicate *predicateTemplate = [NSPredicate
    predicateWithFormat:@"lastName like[c] $LAST_NAME"];

Это эквивалентно созданию переменного выражения непосредственно как показано в следующем примере.

NSExpression *lhs = [NSExpression expressionForKeyPath:@"lastName"];
 
NSExpression *rhs = [NSExpression expressionForVariable:@"LAST_NAME"];
 
NSPredicate *predicateTemplate = [NSComparisonPredicate
    predicateWithLeftExpression:lhs
    rightExpression:rhs
    modifier:NSDirectPredicateModifier
    type:NSLikePredicateOperatorType
    options:NSCaseInsensitivePredicateOption];

Для создания допустимого предиката для оценки против объекта Вы используете NSPredicate метод predicateWithSubstitutionVariables: передать в словаре, содержащем переменные, которыми заменят. (Обратите внимание на то, что словарь должен содержать пары ключ/значение для всех переменных, указанных в предикате.)

NSPredicate *predicate = [predicateTemplate predicateWithSubstitutionVariables:
    [NSDictionary dictionaryWithObject:@"Turner" forKey:@"LAST_NAME"]];

Новый предикат, возвращенный этим примером, lastName LIKE[c] "Turner".

Поскольку словарь замены должен содержать пары ключ/значение для всех переменных, указанных в предикате, если Вы хотите соответствовать нулевое значение, необходимо обеспечить нулевое значение в словаре, как проиллюстрировано в следующем примере.

NSPredicate *predicate = [NSPredicate
    predicateWithFormat:@"date = $DATE"];
predicate = [predicate predicateWithSubstitutionVariables:
    [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"DATE"]];

Предикат, сформированный этим примером, date == <null>.

Сводка строки формата

Важно различить различные типы имеющие значение в строке формата. Отметьте также, что единственные или двойные переменные заключения в кавычки (или переменные строки замены) вызовут %@, %K, или $variable интерпретироваться как литерал в строке формата и так предотвратит любую замену.

@"attributeName == %@"

Этот предикат проверяет ли значение ключа attributeName совпадает со значением объекта %@ это предоставляется во время выполнения как параметр predicateWithFormat:. Обратите внимание на то, что %@ может быть заполнитель для любого объекта, описание которого допустимо в предикате, таково как экземпляр NSDate, NSNumber, NSDecimalNumber, или NSString.

@"%K == %@"

Этот предикат проверяет ли значение ключа %K совпадает со значением объекта %@. Переменные предоставляются во время выполнения как параметры predicateWithFormat:.

@"name IN $NAME_LIST"

Это - шаблон для предиката, проверяющего ли значение ключа name находится в переменной $NAME_LIST (никакие кавычки), который предоставляется при использовании во время выполнения predicateWithSubstitutionVariables:.

@"'name' IN $NAME_LIST"

Это - шаблон для предиката, проверяющего ли постоянное значение 'name' (отметьте кавычки вокруг строки), находится в переменной $NAME_LIST это предоставляется при использовании во время выполнения predicateWithSubstitutionVariables:.

@"$name IN $NAME_LIST"

Это - шаблон для предиката, ожидающего, что значения будут заменены (использование predicateWithSubstitutionVariables:) для обоих $NAME и $NAME_LIST.

@"%K == '%@'"

Этот предикат проверяет ли значение ключа %K равно строковому литералу “%@“(отмечают одинарные кавычки вокруг %@). Ключевое имя %K предоставляется во время выполнения как параметр predicateWithFormat:.