【问题标题】:Core Data Transformable attributes NOT working with NSPredicate核心数据可转换属性不适用于 NSPredicate
【发布时间】:2011-08-31 13:34:54
【问题描述】:

我经常用Transformable代替Core Data attributes,以后可以改一下。

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

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

有人可以解释使用NSPredicate 和Transformable 属性的限制吗?

【问题讨论】:

  • 我测试 uniqueKey == %@ 没问题,并且 MATCHES 包含,好像不成功。

标签: xcode ios core-data nspredicate transformable


【解决方案1】:

注意:我不确定自 2011 年 5 月以来这种情况何时/是否发生了变化(来自 Scott Ahten 接受的答案),但您绝对可以使用 NSPredicate 搜索可转换属性。 Scott 正确解释了为什么您的假设被打破,但是如果 有人可以解释使用带有 Transformable 属性的 NSPredicate 的限制吗? 是您的问题,他暗示这是不可能的,这是不正确的。

由于这是“Core Data transformable value search nspredicate”的第一个 google 搜索结果(我通过搜索来寻找灵感),因此我想添加我的工作答案。

如何使用具有可转换属性的 NSPredicate

简短而令人兴奋的答案:您需要对数据转换器保持聪明。您需要将值转换为包含我称之为“原始识别信息”的 NSData,即可用于重建对象的最小、最具识别性的字节集。长答案,...

首先,考虑:

  • 您的意思是使用可转换属性吗?如果任何受支持的数据类型(甚至是二进制数据)都足够,请使用它。
  • 您了解什么是可转换属性吗?他们如何在商店中打包和解包数据?查看 Apple 文档中的 Non-Standard Persistent Attributes。
    • 读完上面的内容后,问:隐藏受支持类型“支持属性”的自定义代码对你有用吗?可能会使用该技术。

现在,除了这些考虑之外,可转换属性相当巧妙。坦率地说,为 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

【讨论】:

  • 您有任何示例说明查询该类时谓词的实际外观吗?
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    你可以试试这个方法

    NSExpression *exprPath = [NSExpression expressionForKeyPath:@"transformable_field"];
    NSExpression *exprKeyword = [NSExpression expressionForConstantValue:nsdataValue];
    NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:exprPath rightExpression:exprKeyword modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:0];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-20
      • 1970-01-01
      • 1970-01-01
      • 2018-02-10
      • 2013-01-12
      相关资源
      最近更新 更多