Creating Predicates
OSXDEV
Predicates Programming Guide로 이동
코코아에서 프리디케이츠를 만드는 방법은 세가지가 있다: 포맷 스트링을 사용; 코드로 직접 그리고 프리디케이트 템플릿으로부터. 그러나 모든 사용가능한 프리디케이트 쿼리가 모든 종류의 backing store에서 지원되지는 않는다는 것을 명심한다.
목차 |
[편집] Creating a Predicate Using a Format String
포맷 스트링을 이용해 프리디케이트를 만드는 것은 쉽고 빠르게 코딩할 수 있다. 다양한 대체변수들이 충분한 유연성을 제공하지만, 주로 미리 지정된 쿼리 문 사용에 최적화 되어있다. 이 기술의 단점은 스트링내에서 에러를 발생시키지 않도록 유의해야한다는 것이다- 런타임 이전에 실수를 발견하기가 어렵다.
NSPredicate는 스트링으로부터 프리디케이트를 직접 생성하고 부가적으로 변수를 대체할 수 있는 수많은 predicateWithFormat... 형식의 클래스 메소드들을 제공한다. 런타임 시에, 변수 대체가-있다면- 수행되고, 결과 스트링이 해당 프리디케이트와 공식expression 오브젝트를 만들기 위해 파싱된다. 프리디케이트 포맷 스트링 문법은 일반적인 공식의 문법과 다르다는 것을 명심한다. 일반적인 공식의 문법은 ICU에 의해 정의된다 - http://icu.sourceforge.net/userguide/regexp.html를 보라.
프리디케이트 스트링 파서는 공백 무시, 키워드에 대해 대/소문자 무시. 그리고 내부적 괄호문nested parenthetical 지원, printf스타일의 매개변수 지원(%x, %@) - Formatting String Objects를 보라. 변수는 ($VARIABLE_NAME처럼) $로 시작한다 - 자세한 내용은 “Creating Predicates Using Predicate Templates”를 보라. 파서가 의미를 고려해서 타입 체크를 하지는 않는 다는 것을 명심해라. 적당한 공식을 만들기 위해 최대한 검사를 하겠지만, 특히 대체 변수가 있는 경우에는, 런타임 에러가 발생할 수 있다. 모든 스트링 문법과 모든 연산자들의 리스트는 “Predicate Format String Syntax.”을 보라. 다음 예문은 두개의 comparisoon 프리디케이츠로 compound 프리디케이트를 만든다.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(lastName like[cd] %@) AND (birthday > %@)", lastNameSearchString, birthdaySearchDate];
이 예제에서 like[cd]는 "case와 diacritic 구별없는 like"를 뜻한다.
[편집] String Constants, Variables, and Wildcards
스트링 상수는 공식내에서 따옴표 처리되어야만 한다 - 외 따옴표나 쌍 따옴표 모두 사용가능하지만 반드시 적당한 쌍을 이루어야 한다(즉, 쌍따옴표(")는 외 따옴표(')와 쌍을 이룰 수 없다).%@를 이용해 대체변수을 사용하면(firstName like %@ 처럼), 따옴표는 자동으로 더해진다. 다음 예제처럼 포맷 스트링 안에 스트링 상수를 사용하려면 직접 quote를 해야한다.
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:@"prefixxxxxxxsuffix"];
이 예제에서, 변수 대체시 프리디케이트 스트링 SELF LIKE[c] "prefix*sufix"를 만들어 냈으며, 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];
포맷 스트링에서의 변수 대체와 변수 공식variable expression간의 차이점을 잘 알고 있어야 한다. 다음은 오른쪽 편에 변수 공식을 가지는 프리디케이션을 만들어내는 코드조각이다.
predicate = [NSPredicate predicateWithFormat:@"lastName like[c] $LAST_NAME"];
변수 공식에 대해 자세히 알고 싶으면 “Creating Predicates Using Predicate Templates”를 보라.
[편집] Boolean Values
다음의 예제처럼 Boolean값이 맞는지를 지정하고 테스트 할 수 있다.
NSPredicate *newPredicate =
[NSPredicate predicateWithFormat:@"anAttribute == %@", [NSNumber numberWithBool:aBool]];
NSPredicate *testForTrue = [NSPredicate predicateWithFormat:@"anAttribute == YES"];
[편집] Dynamic Property Names
스트링 변수들은 %@를 통해 포맷 스트링 안으로 대체될 때 따옴표에 의해 둘러싸여져야 하므로, 다음 예제에서 처럼, %@를 동적인 프라퍼티 이름을 지정하는 데 사용할 수 없다.
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을 둘러싸고 있는 따옴표가 없다는 것에 주의하라).
[편집] Creating Predicates Directly in Code
프리디케이트와 공식 인스턴스를 코드에서 직접생성할 수 있다. NSComparisonPredicate와 NSCompoundPredicate가 각각 합성compound와 비교comparison 프리디케이트를 만드는 편리한 메소드들을 제공한다. NSComparisonPredicate는 간단한 등식에서부터 커스텀 함수까지 갖가지 오퍼레이터를 제공한다.
다음 예제는 (revenue >= 1000000) and (revenue < 100000000)를 나타내는 프리디케이트를 어떻게 만드는 지를 보여준다. 똑같은 왼쪽 표현이 두개의 비교 프리디케이트 모두에 사용되었다는 것을 눈여겨 보라.
NSExpression *lhs = [NSExpression expressionForKeyPath:@"revenue"];
NSExpression *greaterThanRhs = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:10000000]];
NSPredicate *greaterThanPredicate = [NSComparisonPredicate
predicateWithLeftExpression:lhs
rightExpression:greaterThanRhs
modifier:NSDirectPredicateModifier
type:NSGreaterThanOrEqualToPredicateOperatorType
option: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]];
이 기술의 단점은 - 보이는 대로 너무 많은 코드를 작성해야 한다는 것이다. 장점은 런타임시에나 찾아지는 철자등의 에러가 찾아진다는 것과 스트링 파서에 의존하는 것보다 빠를 것이라는 것이다.
이 기법은 프리디케이트 빌더 에서처럼, 프리디케이트 그 자체를 만드는 것이 동적일 때 가장 유용하다.
[편집] Creating Predicates Using Predicate Templates
프리디케이트 템플릿은 사용은 쉽지만 잠재적 에러 가능성이 있는 포맷 스트링 기반의 기법과 에러 검출이 가능한 순수 코딩 기법 사이의 좋은 합일점을 제안한다. 프리디케이트 템플리트는 단순히 변수 표현을 포함하는 프리디케이트이다.(CoreData 프레임워크를 사용한다면 Xcode의 디자인 툴을 이용해서 모델에 패치 요청을 할 수 있는 프리디케이트 템플릿을 더할 수 있다- Managed Object Models를 보라.)
다음 예제는 오른쪽 편에 변수 공식을 가진 프리디케이트를 만들기 위해 포맷 스트링을 사용했다.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"lastName like[c] $LAST_NAME"];
이것은 다음예제에서 변수 공식을 직접 생성하기 위한 코드들과 동일하다.
NSExpression *lhs = [NSExpression expressionForKeyPath:@"lastName"]; NSExpression *rhs = [NSExpression expressionForVariable:@"LAST_NAME"]; NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:lhs rightExpression:rhs modifier:NSDirectPredicateModifier type:NSLikePredicateOperatorType options:NSCaseInsensitivePredicateOption];
오브젝트에 대해 평가할 적당한 프리디케이트를 만들기 위해, NSPredicate의 메소드 predicateWithSubstitutionVariables:를 사용하여 대체될 변수들을 포함하고 있는 딕셔너리로부터 값을 넘긴다. (딕셔네리는 프리디케이트에서 지정한 모든 변수에 대해 키-값 쌍을 가져야 한다는 것을 명심)
predicate = [predicate predicateWithSubstitutionVariables: [NSDictionary dictionaryWithObject:@"Turner" forKey:@"LAST_NAME"]];l
이 예제로부터 리턴디는 프리디케이트는 lastName LIKE[c] "Turner"와 같다.
대체되는 딕셔너리가 프리디케이트에서 지정된 모든 변수들에 대해 키-값 쌍을 가져야만 하기 때문에, 다음 예제 처럼 null값에 맞추려고 하면 덱셔너리에서 null값을 제공해야 한다.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"date = $DATE"]; predicate = [predicatge predicateWithSubstitutionVariables: [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"DATE"]];
이 예제를 통해 형성된 프리디케이트는 date == <null>이다.
[편집] Format String Summary
포맷 스트링에서 서로 다른 타입의 값들을 구별하는 것은 매우 중요하다. 외 따옴표 도는 쌍 따옴표 변수들은(또는 대체 변수 스트링들) %@, %K 또는 $variable이 문자 그대로 포맷 스트링에서 번역되도록 하여 정상적인 대체가 일어나지 않도록 한다는 것을 명심하라,
@"attributeName == %@"
이 프리디케이트는 attributeName키의 값이 런타임시에 predicateWithFormat:의 매개변수로 제공되는 %@ 오브젝트의 값과 같은지를 체크한다. %@가 디스크립션이 프리디케이트안에서 사용가능한 모든 오브젝트에 대한 placeholder가 될 수 있다는 것을 주의하라.예를 들면 NSDate, NSNumber, NSDecimalNumber, 또는 NSStirng의 인스턴스처럼.
@"%K == %@"
이 프리디케이트는 %K의 키 값이 %@ 오브젝트의 값과 같은지를 체크한다. 변수는 predicateWithFormat:의 매개변수로 런타임시에 제공된다.
@"name IN $NAME_LIST"
name 키의 값이 런타임시에 predicateWithSubstitutionVariables:를 통해 제공되는 $NAME_LIST(따옴표 없음)안에 있는지를 체크하는 프리디케이트를 위한 템플리트이다.
@"'name' IN $NAME_LIST"
상수 값 'name'(스트링을 따옴표가 둘러싸고 있음)이 키의 값이 런타임시에 predicateWithSubstitutionVariables:를 통해 제공되는 $NAME_LIST안에 있는지를 체크하는 프리디케이트를 위한 템플리트이다.
@"$name IN $NAME_LIST"
$NAME과 $NAME_LIST 모두의 값이 (predicateWithSubstitutionVariables:를 통해) 대체되는 것을 예상하는 프리디케이트를 위한 템플리트이다.
@"%K == '%@'"
이 프리디케이트는 %K 키의 값이 "%@"( %@주위에 외따옴표에 주의) 문자 스트링과 같은지를 체크한다. %K의 키 이름은 predicateWithFormat:의 매개변수로 런타임시에 공급된다.




