注:2011年5月以降にこれがいつ/変更されたかはわかりませんが(Scott Ahtenの受け入れられた回答から)、変換可能な属性についてNSPredicateを使用して絶対に検索できます。スコットはあなたの仮定が破られた理由を正しく説明しましたが、誰かがTransformable属性でNSPredicateを使用することの制限を説明できますか?あなたの質問でした、彼はそれが不可能であるとほのめかしました、そしてそれは間違っています。
これは「 CoreData変換可能値検索nspredicate 」(インスピレーションを見つけるために検索したもの)の最初のグーグルヒットであるため、実用的な答えを追加したいと思いました。
変換可能なプロパティでNSPredicateを使用する方法
短くて頭の痛い答え:データトランスフォーマーについて賢くする必要があります。値をNSDataに変換する必要があります。これには、「プリミティブ識別情報」と呼ばれるもの、つまり、オブジェクトの再構築に使用できる最小で最も識別力のあるバイトのセットが含まれます。長い答え、..。
まず、次のことを考慮してください。
- 実際に変換可能な属性を使用するつもりでしたか?サポートされているデータ型(バイナリデータでも)で十分な場合は、それを使用してください。
- 変換可能な属性が実際に何であるかを理解していますか?ストアとの間でデータをどのようにパックおよびアンパックしますか?Appleのドキュメントで
非標準の永続属性を確認してください。
- 上記を読んだ後、質問してください:サポートされているタイプの「バッキング属性」を非表示にするカスタムコードは機能しますか?おそらくそのテクニックを使用します。
さて、これらの考慮事項を過ぎると、変換可能な属性はかなり洗練されています。率直に言って、Fooインスタンス用のNSValueTransformer "FooToData"をNSDataに書き込むことは、多くのアドホックカスタムコードを記述するよりもクリーンに見えました。登録されたNSValueTransformerを使用してデータを変換する必要があることをCoreDataが認識していないケースは見つかりませんでした。
先に進むには、これらの懸念に対処するだけです。
- 使用するトランスフォーマーをCoreDataに伝えましたか?テーブルビューでコアデータモデルを開き、エンティティをクリックし、属性をクリックして、[データモデルインスペクター]ペインをロードします。[属性タイプ:変換可能]で、トランスフォーマーに[名前]を設定します。
- デフォルトのトランスフォーマーを使用するか(これも以前のAppleドキュメントを参照)、独自のトランスフォーマーを作成します--transformedValue:はNSDataを返す
必要があります。
- NSKeyedUnarchiveFromDataTransformerNameはデフォルトのトランスフォーマーであり、十分でない場合や、2つの類似したオブジェクトが等しい場合に異なる可能性がある、やや一時的なインスタンスデータを描画する場合があります。
- 変換された値には、「プリミティブ識別情報」のみが含まれている必要があります。ストアはバイトを比較するため、すべてのバイトがカウントされます。
- トランスフォーマーをグローバルに登録することもできます。私は実際にアプリの他の場所でそれらを再利用するので、これを行う必要があります-例:
NSString *name = @"FooTrans"; [NSValueTransformer setValueTransformer:[NSClassFromString(name) new] forName:name];
おそらく、トランスフォームを使用したくないでしょう。たとえば、主キー情報がトランスフォーマーを使用する大規模なインポートなど、クエリの多いデータ操作です。
そして最後に、これを使用して、NSPredicates(たとえば、 "%K ==%@")を使用したモデルの高レベルオブジェクト属性が等しいかどうかをテストします。これは正常に機能します。さまざまな一致する用語のいくつかを試したことはありませんが、それらが時々機能し、他の用語が機能しなくても驚かないでしょう。
NSURLからNSDataへのトランスフォーマーの例を次に示します。文字列を保存しないのはなぜですか?ええ、それは問題ありません-これは、保存された属性をマスクするカスタムコードの良い例です。この例は、文字列化されたURLに追加のバイトが追加され、ファイルURLであるかどうかを記録することを示しています。これにより、オブジェクトが解凍されたときに使用するコンストラクターを知ることができます。
// URLToDataTransformer.h - interface
extern NSString *const kURLToDataTransformerName;
@interface URLToDataTransformer : NSValueTransformer
@end
..。
// URLToDataTransformer.m - implementation
#import "URLToDataTransformer.h"
NSString *const kURLToDataTransformerName = @"URLToDataTransformer";
@implementation URLToDataTransformer
+ (Class)transformedValueClass { return [NSData class]; }
+ (BOOL)allowsReverseTransformation { return YES; }
- (id)transformedValue:(id)value
{
if (![value isKindOfClass:[NSURL class]])
{
// Log error ...
return nil;
}
NSMutableData *data;
char fileType = 0;
if ([value isFileURL])
{
fileType = 1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value path] dataUsingEncoding:NSUTF8StringEncoding]];
}
else
{
fileType = -1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value absoluteString] dataUsingEncoding:NSUTF8StringEncoding]];
}
return data;
}
- (id)reverseTransformedValue:(id)value
{
if (![value isKindOfClass:[NSData class]])
{
// Log error ...
return nil;
}
NSURL *url = nil;
NSData *data = (NSData *)value;
char fileType = 0;
NSRange range = NSMakeRange(1, [data length]-1);
[data getBytes:&fileType length:1];
if (1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL fileURLWithPath:str];
}
else if (-1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL URLWithString:str];
}
else
{
// Log error ...
return nil;
}
return url;
}
@end