【问题标题】:Why is my transformable Core Data attribute not using my custom NSValueTransformer?为什么我的可转换核心数据属性不使用我的自定义 NSValueTransformer?
【发布时间】:2010-12-08 14:07:48
【问题描述】:

我有一个具有相当简单数据模型的 Core Data 应用程序。我希望能够将 NSImage 的实例作为 PNG Bitmap NSData 对象存储在持久存储中,以节省空间。

为此,我编写了一个简单的 NSValueTransformer 来将 NSImage 转换为 PNG 位图格式的 NSData。我在我的 App 委托中使用此代码注册值转换器:

+ (void)initialize
{
    [NSValueTransformer setValueTransformer:[[PNGDataValueTransformer alloc] init] forName:@"PNGDataValueTransformer"];
}

在我的数据模型中,我将图像属性设置为可转换,并将PNGDataValueTransformer 指定为值转换器名称。

但是,我的自定义值转换器没有被使用。我知道这一点,因为我已将日志消息放在我的值转换器的 -transformedValue:-reverseTransformedValue 方法中,这些方法没有被记录,并且保存到磁盘的数据只是一个存档的 NSImage,而不是它应该的 PNG NSData 对象是。

为什么这不起作用?

这是我的价值转换器的代码:

@implementation PNGDataValueTransformer

+ (Class)transformedValueClass
{
    return [NSImage class];
}

+ (BOOL)allowsReverseTransformation
{
    return YES;
}

- (id)transformedValue:(id)value
{
    if (value == nil) return nil;
    if(NSIsControllerMarker(value))
        return value;
    //check if the value is NSData
    if(![value isKindOfClass:[NSData class]])
    {
        [NSException raise:NSInternalInconsistencyException format:@"Value (%@) is not an NSData instance", [value class]];
    }
    return [[[NSImage alloc] initWithData:value] autorelease];
}

- (id)reverseTransformedValue:(id)value;
{
    if (value == nil) return nil;
    if(NSIsControllerMarker(value))
        return value;
    //check if the value is an NSImage
    if(![value isKindOfClass:[NSImage class]])
    {
        [NSException raise:NSInternalInconsistencyException format:@"Value (%@) is not an NSImage instance", [value class]];
    }
    // convert the NSImage into a raster representation.
    NSBitmapImageRep* bitmap    = [NSBitmapImageRep imageRepWithData: [(NSImage*) value TIFFRepresentation]];
    // convert the bitmap raster representation into a PNG data stream
    NSDictionary* pngProperties = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:NSImageInterlaced];
    // return the png encoded data
    NSData* pngData             = [bitmap representationUsingType:NSPNGFileType properties:pngProperties];
    return pngData;
}

@end

【问题讨论】:

    标签: objective-c cocoa image core-data


    【解决方案1】:

    如果我没记错的话,你的价值转换器有一个相反的方向。我在我的应用程序中做同样的事情,使用如下代码:

    + (Class)transformedValueClass 
    {
     return [NSData class]; 
    }
    
    + (BOOL)allowsReverseTransformation 
    {
     return YES; 
    }
    
    - (id)transformedValue:(id)value 
    {
     if (value == nil)
      return nil;
    
     // I pass in raw data when generating the image, save that directly to the database
     if ([value isKindOfClass:[NSData class]])
      return value;
    
     return UIImagePNGRepresentation((UIImage *)value);
    }
    
    - (id)reverseTransformedValue:(id)value
    {
     return [UIImage imageWithData:(NSData *)value];
    }
    

    虽然这适用于 iPhone,但您应该能够在适当的位置交换 NSImage 代码。我还没有测试我的 Mac 实现。

    我所做的只是将我的图像属性设置为在数据模型中可转换,并指定转换器的名称。我不需要像您在 +initialize 方法中那样手动注册值转换器。

    【讨论】:

    • 谢谢布拉德。我试过了,但没有任何区别,我的价值转换器被忽略了。
    【解决方案2】:

    注册转换器似乎对 Core Data 是否使用它没有影响。 我一直在玩 PhotoLocations 示例代码,删除变压器注册没有任何效果。只要您的 ValueTransformerName 是您的类的名称,并且您的转换器的实现包含在目标中,它就应该可以工作。

    如果转换器中没有代码执行,那么转换器中的代码是无关紧要的。问题必须在核心数据堆栈中的其他地方,或者在变压器的声明中。

    【讨论】:

    • 这里也一样!你找到解决办法了吗?
    【解决方案3】:

    事实证明,这实际上是框架中的一个错误。在 Cocoa-Dev 邮件列表中查看 Apple 员工的这篇帖子:

    http://lists.apple.com/archives/Cocoa-dev/2009/Dec/msg00979.html

    【讨论】:

      【解决方案4】:

      您需要在运行时显式注册您的转换器。

      这样做的好地方是在你的 NSManagedObject 实体子类中重写类初始化方法。如前所述,它是已知的核心数据错误。以下是 Apple 位置代码示例中的关键代码,它经过测试并且可以工作: http://developer.apple.com/library/ios/#samplecode/Locations/Introduction/Intro.html

      + (void)initialize {
          if (self == [Event class]) {
              UIImageToDataTransformer *transformer = [[UIImageToDataTransformer alloc] init];
              [NSValueTransformer setValueTransformer:transformer forName:@"UIImageToDataTransformer"];
          }
      }
      

      【讨论】:

      • 是的,我知道这一点,我正在这样做。
      • 就我而言,这正是问题所在。您还可以检查转换器名称是否与您在数据模型中声明的名称匹配,以及您是否没有反转方法的主体:transformedValue 和 reverseTransformedValue。
      【解决方案5】:

      如果您的代码中没有其他地方明确使用 PNGDataValueTransformer 类,则永远不会调用该类的 +initialize 方法。在您的 Core Data 模型中指定名称也不会触发它 - 它只会尝试查找该名称的值转换器,这将返回 nil,因为尚未在该名称下注册任何转换器实例。

      如果这确实是您的情况,只需在您的数据模型被访问之前,在代码中的某处添加对 [PNGDataValueTransformer initialize] 的调用,例如在使用此数据模型的任何类的 +initialize 方法中。这应该会触发值转换器实例的创建和注册,以便 Core Data 可以在需要时访问它。

      【讨论】:

      • 嗨,Brian,+initialize 方法在我的应用程序委托中,而不是值转换器中,我绝对可以验证它是否被调用。如果我在我的 NSValueTransformer 的-init 方法中放置一个断点,它肯定会被初始化。如果我将属性设置为“二进制”类型并将我的值转换器应用于 IB 中的每个绑定,它工作正常。我只是不明白为什么当我将属性类型指定为 Transformable 时没有使用自定义转换器。
      【解决方案6】:

      查看示例代码here

      这是你想要的吗?

      @implementation UIImageToDataTransformer
      
      
      + (BOOL)allowsReverseTransformation {
          return YES;
      }
      
      + (Class)transformedValueClass {
          return [NSData class];
      }
      
      
      - (id)transformedValue:(id)value {
          NSData *data = UIImagePNGRepresentation(value);
          return data;
      }
      
      
      - (id)reverseTransformedValue:(id)value {
          UIImage *uiImage = [[UIImage alloc] initWithData:value];
          return [uiImage autorelease];
      }
      

      【讨论】:

        猜你喜欢
        • 2011-12-14
        • 1970-01-01
        • 1970-01-01
        • 2011-05-04
        • 1970-01-01
        • 1970-01-01
        • 2011-08-31
        • 1970-01-01
        • 2018-11-20
        相关资源
        最近更新 更多