Predicate Programming Guideu一部意訳

Predicate Programming Guide内の、
Creating Predicatesの章を1部意訳しました。
(なんとか自分が読める程度の意訳、良い訳があれば是非教えて下さい。)

目次






述語の作成(Creating Predicates)

Cocoaの述語を作成するには、3つの方法があります。
・フォーマット文字列を使用
・コード内に直接記述
・述語テンプレートから作成





フォーマット文字列を使って述語を作成する

文字列から直接述語を作成する為に、
NSPredicateクラスのメソッドpredicateWithFormatを使用することができます。
必要に応じて、変数置換を使用して、文字列として述語を定義します。

実行時に、変数置換が実行できた場合、
結果文字列は対応する述語と表現オブジェクトを作成するために解析されます。
次の例は、2つの比較述部を持つ複合述語を作成します。

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

(例の中の、like[cd]は"発音区別記号や大文字小文字を区別しない"という事を意味します。)
文字列構文と使用可能な全ての演算子リストについての完全な説明は、
"Predicate Format String Syntax"を参照して下さい

重要: 述語の形式の文字列の構文は正規表現の構文とは異なります。
正規表現の構文は、ICU-SEE http://www.icu-project.org/userguide/regexp.htmlで定義されています。

述語文字列のパーサーは、キーワードに関して空白、大文字と小文字を区別しません。
そしてネストされた括弧表現をサポートしています。
また、printfスタイル形式の引数(%xと%@のような)をサポートしています。
"Formatting String Objects"を参照
$で表記された変数(例: $ VARIABLE_NAME)の詳細は、
Creating Predicates Using Predicates”を参照





パーサは、どんな型チェックも実行しません。
それは、適切な式を作成するための最良の推測作業を行いますが、
特に変数置換の場合にランタイムエラーが生成される可能性があります。

このアプローチは一般的に定義済みのクエリ条件に最も使用されます。
変数置換はかなりの柔軟性を可能にしますが、
この手法の欠点は、文字列にエラーがでることを避けるように注意しなければならない事で、
ミスは実行時まで発見されません。
【目次に戻る】




文字列定数、変数、ワイルドカード

式の中の文字列定数は単一引用符と二重引用符で囲む必要があります。
両方の記述が許容されますが、適切に組み合わせる必要があります。
(つまり、二重引用符(")は単一引用符(')と一致しません)
もし%@を使って変数置換をする場合(例えば、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"];

変数表現の詳細については、 "Creating Predicates Using Predicate Templates"を参照してください。
【目次に戻る】




ブーリアン

ブール値指を指定して等価性をテストする場合、次に示す例のようにします。

    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は、単純な等価テストからカスタム関数までの演算子を提供しています。
次の例は、>|objc|(revenue >= 1000000) and (revenue < 100000000). ||<を表現する述語を作成する方法を示します。
両方の比較が述部に同じ左側の式が使用されていることに注意してください。

//revenueというキーパスからNSExpressionのインスタンスを生成
NSExpression *lhs = [NSExpression expressionForKeyPath:@"revenue"];

 //定数100万からNSExpressionのインスタンスを生成
NSExpression *greaterThanRhs = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:1000000]];

//左辺にrevenue、右辺に100万を使い、>=を指定して述語を生成
NSPredicate *greaterThanPredicate = [NSComparisonPredicate
    predicateWithLeftExpression:lhs
    rightExpression:greaterThanRhs
    modifier:NSDirectPredicateModifier
    type:NSGreaterThanOrEqualToPredicateOperatorType
    options:0];
 
 //定数1000万からNSExpressionのインスタンスを生成
NSExpression *lessThanRhs = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:100000000]];
//左辺には又revenue、右辺に1000万を使い < を指定して述語を生成
NSPredicate *lessThanPredicate = [NSComparisonPredicate
    predicateWithLeftExpression:lhs
    rightExpression:lessThanRhs
    modifier:NSDirectPredicateModifier
    type:NSLessThanPredicateOperatorType
    options:0];
 //2つの述語(revenue >= 1000000)と(revenue < 10000000)をandを間に入れて合成する
NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
    [NSArray arrayWithObjects:greaterThanPredicate, lessThanPredicate, nil]];

この手法の欠点は、すぐに明らかになります。
あなたは多くのコードを記述する必要があります。
利点は、実行時に発見されるスペルや他の誤植が少ない傾向があるということです。
又、文字列の解析に応じてより高速になる可能性があります。
Predicate builderのように、
述語の作成自体が動的である場合、この手法は有用である可能性が最も高いです。
【目次に戻る】





述語テンプレートを使用して述語を作成する

述語テンプレートは、使いやすいが潜在的にエラーが発生しやすい形式の文字列ベースの手法と、
コードに集約された純粋なコーディングのアプローチの間の良好な妥協点を提供します。
述語のテンプレートは、単に変数表現が含まれている述語です。
(あなたがCore Dataフレームワークを使用している場合、
モデルへの要求をフェッチする述語テンプレートを追加する為に、
Xcodeの設計ツールを使用することができます。)
詳細は“Managed Object Models” を参照して下さい。
次の例では、変数式で右辺と述語を作成するにはフォーマット文字列を使用しています。

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".です。
null値を一致させたい場合、置換辞書は、
述語で指定されたすべての変数のキーと値のペアが含まれている必要がありますので、
次の例に示すように、あなたは、ディクショナリ内のnull値を提供する必要があります。

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

この例で形成された述語は date == .になります。
【目次に戻る】

気が向けば続きます、


参考サイト:NSPredicate
【Natsu's note】テンプレートを利用した生成方法(パフォーマンス改善)

【Cocoaの日々】1対多関連のエンティティの検索条件見本(集計関数使用)
【こたつつきみかん】NSPredicateの使い方

hippos-lab:NSPredicateの正規表現

Second Flush:NSPredicateクラス一部訳

Predicate Programming Guide(英語)

NSPredicate Class Reference