9

我经常使用Transformablefor Core Data attributes,所以我以后可以更改它们。

但是,如果我想使用NSPredicatefind NSManagedObject、 using"uniqueKey == %@""uniqueKey MATCHES[cd] %@",它似乎无法正常工作。

它总是会错过匹配的对象,直到我将匹配对象的 uniqueKey 的属性更改为具有特定类,例如NSString, 或NSNumber.

有人可以解释使用NSPredicatewithTransformable属性的限制吗?

4

3 回答 3

4

可转换属性通常作为存档的二进制数据保存。因此,您试图将 NSData 的实例与 NSString 或 NSNumber 的实例进行比较。

由于这些类以不同的方式解释相同的数据,因此它们不被视为匹配项。

于 2011-05-24T06:50:38.823 回答
4

注意:我不确定自 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
于 2014-02-16T18:17:19.013 回答
-1

你可以试试这种方式

NSExpression *exprPath = [NSExpression expressionForKeyPath:@"transformable_field"];
NSExpression *exprKeyword = [NSExpression expressionForConstantValue:nsdataValue];
NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:exprPath rightExpression:exprKeyword modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:0];
于 2012-06-24T02:17:34.850 回答