Monday, April 29, 2013

Создание предикатов Cocoa http://macbug.ru/cocoa/predcreate

http://macbug.ru/cocoa/predcreate

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

Cocoa

Есть три способа создания предиката в Cocoa: используя формат строки, непосредственно в коде, и с шаблоном предиката.

Создание предикатов с помощью формата строки

Вы можете использовать методы класса NSPredicate вида predicateWithFormat... для создания предиката непосредственно из строки. Необходимо определить предикат в виде строки, при необходимости используя подстановки. Во время выполнения выполняются подстановки переменных, если таковые имеются, и в результате эта строка может быть использована для создания соответствующего предиката и выражений объектов. В следующем примере создается соединение предиката с двумя предикатами сравнения.

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

(в примере like[cd] означает "без учета регистра и диакритических знаков").

Полное описание синтаксиса строки и список операторов, доступных в разделе "Пердикаты, синтаксис формата строки".

Важно. Синтаксис формата строки предиката отличается от синтаксиса регулярных выражений.

Синтаксический анализатор строки предиката разбирает пробельные символы, регистр по отношению к ключевым словам, а также поддерживает вложенные в скобки выражения. Он также поддерживает в стиле printf формат аргументов (например, x% и %@) см. "Форматирование строковых объектов". Переменные обозначаются $ (например, $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"];  

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

Можно указать и проверить равенство логических значений, как показано в следующем примере:

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:      [NSArray arrayWithObjects:greaterThanPredicate, lessThanPredicate, nil]];  

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

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

Шаблоны предиката предлагают хороший компромисс между простыми в использовании, но потенциально подверженными ошибкам строкам формата на основе подхода техники интенсивного и чистого кодирования кода. Шаблон предиката - просто предикат, который включает в себя переменные выражения. (Если вы используете Core Data framework, вы можете использовать инструменты разработки 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".

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

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

новый предикат возвращаемый этим примером date == <null>.

Формат строки, итоги

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

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

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

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

@"'name' IN $NAME_LIST"
Это шаблон для предиката, который проверяет наличие постоянной величины 'name' (обратите внимание на кавычки вокруг строки) в переменной $NAME_LISTкоторая предоставляется во время выполнения predicateWithSubstitutionVariables:.

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

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

No comments:

Post a Comment