注意:我不确定自 5/2011 以来何时/是否发生了变化(来自 Scott Ahten 接受的答案),但您绝对可以使用 NSPredicate 搜索可转换属性。斯科特正确地解释了为什么你的假设被打破了,但是如果有人可以解释使用带有可转换属性的 NSPredicate 的限制吗?是你的问题,他暗示这是不可能的,这是不正确的。
由于这是“ Core Data transformable value search nspredicate ”(我搜索的内容试图寻找灵感)的第一个谷歌热门,我想添加我的工作答案。
如何使用具有可转换属性的 NSPredicate
简短而令人兴奋的答案:您需要对数据转换器保持聪明。您需要将值转换为包含我称之为“原始识别信息”的 NSData,即可用于重建对象的最小、最具识别性的字节集。长答案,...
首先,考虑:
- 您是否真的打算使用可转换的属性?如果任何支持的数据类型——甚至是二进制数据——就足够了,使用它。
- 你了解什么是可转换的属性吗?他们如何在商店中打包和解包数据?查看Apple 文档中的非标准持久属性。
- 看完上面的内容,请问:隐藏支持类型“支持属性”的自定义代码对你有用吗?可能会使用该技术。
现在,抛开这些考虑,可转换的属性相当巧妙。坦率地说,为 Foo 实例编写一个 NSValueTransformer "FooToData" 到 NSData 似乎比编写大量临时自定义代码更干净。我还没有发现 Core Data 不知道它需要使用注册的 NSValueTransformer 转换数据的情况。
继续简单地解决这些问题:
- 你有告诉 Core Data 使用什么转换器吗?在表格视图中打开 Core Data 模型,单击实体,单击属性,加载 Data Model Inspector 窗格。在“属性类型:可转换”下,将“名称”设置为您的转换器。
- 使用默认转换器(同样,请参阅之前的 Apple 文档)或编写您自己的转换器——transformedValue:必须返回 NSData。
- NSKeyedUnarchiveFromDataTransformerName是默认的转换器,可能不够用,或者可能会引入一些短暂的实例数据,这会使两个相似的对象在相等时有所不同。
- 转换后的值应该只包含——我称之为——“原始识别信息”。存储将比较字节,因此每个字节都很重要。
- 您也可以在全球范围内注册您的变压器。我必须这样做,因为我实际上在应用程序的其他地方重用了它们——例如
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