2010-05-21 97 views
2

我试图在由sqlite数据库支持的核心数据存储中存储PNG图像。由于我打算在iPhone上使用此数据库,因此无法直接存储NSImage对象。我想使用绑定和NSValueTransformer子类来处理从NSImage(通过我的GUI上的Image well获得)转换为包含图像的PNG二进制表示的NSData的转码。我写了下面的代码为NSValueTransformer核心数据,绑定,值转换器:保存时崩溃


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

+ (BOOL)allowsReverseTransformation 
{ 
    return YES; 
} 

- (id)transformedValue:(id)value 
{ 
    if (value == nil) return nil; 

    return [[[NSImage alloc] initWithData:value] autorelease]; 
} 

- (id)reverseTransformedValue:(id)value 
{ 
    if (value == nil) return nil; 

if(![value isKindOfClass:[NSImage class]]) 
{ 
    NSLog(@"Type mismatch. Expecting NSImage"); 
} 

NSBitmapImageRep *bits = [[value representations] objectAtIndex: 0]; 

NSData *data = [bits representationUsingType:NSPNGFileType properties:nil]; 

    return data; 
} 

该模型具有此NSValueTransformer配置变形特性。在Interface Builder中,表格列和图像井都绑定到该属性,并且都具有正确的值转换器名称(图像中放置的图像很好地显示在表格列中)。每次添加图像或重新载入行时都会注册并调用转换器(使用NSLog()调用进行检查)。当我试图保存管理对象时,问题就出现了。控制台输出显示错误消息:

[NSImage中长度]:无法识别的选择发送到实例0x1004933a0

好像核心数据使用值变压器,以获得NSImage背面从NSData和然后尝试保存NSImage而不是NSData

有可能的解决方法,如在this post中提出的解决方法,但我真的想明白为什么我的方法是瑕疵。

在此先感谢您的想法和解释。

回答

1

我最终得到它的工作(最好睡上它)。有两个问题。第一个是我在IB绑定和核心数据模型中都指定了相同的值转换器,这是多余的。

我的理解是,IB绑定指定值转换器实际上在视图和控制器之间转换值,而核心数据值转换器充当管理对象和持久存储之间的中间人。

为了让事情变得更糟,第二个问题是我的价值变压器倒过来。在保存对象(管理对象 - >存储)时发送transformValue消息,并且在从存储中加载值时发送reverseTransformedValue,这与将视图对象绑定到模型对象时使用的转换器的方向相反。我得到了暗示从core data programming guide在那里你可以阅读下面的略带神秘的注意事项:

要点:虽然默认变压器是NSKeyedUnarchiveFromDataTransformerName指定的变压器,该变压器在反向实际使用。如果明确指定默认的变压器,核心数据会用它“错误的方向”。

即使我的程序工作,到目前为止,我想有从别人的确认与核心数据的经验,我会非常感谢您能否指出我可能错过的一些关于此事的文档。

在此先感谢。

工作代码:


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

+ (BOOL)allowsReverseTransformation 
{ 
    return YES; 
} 

- (id)reverseTransformedValue:(id)value 
{ 
    if (value == nil) return nil; 

    return [[[NSImage alloc] initWithData:value] autorelease]; 
} 

- (id)transformedValue:(id)value 
{ 
    if (value == nil) return nil; 

    if(![value isKindOfClass:[NSImage class]]) 
    { 
     NSLog(@"Type mismatch. Expecting NSImage"); 
    } 

    NSBitmapImageRep *bits = [[value representations] objectAtIndex: 0]; 

    NSData *data = [bits representationUsingType:NSPNGFileType properties:nil]; 

    return data; 
} 

+0

我没有指定变压器两次,并得到相同的错误。颠倒transformedValue:和reverseTransformedValue:取得了诀窍。非常感谢! – MartinW 2014-11-05 15:06:23

1

在transformedValue:你直接从NSData到NSImage,但在reverseTransformedValue:你从NSImage到NSBitmapImageRep到NSData。所以他们不一起工作,因为他们使用不同的方法。模型中的数据实际上是NSBitmapImageRep数据而不是NSImage数据。这两者需要彼此完全相反。

顺便说一下,我最近在另一篇文章中发布了一个变压器。你可以看到它here。当然你根本不需要定制变压器,因为你可以使用NSKeyedArchiver。 NSImage遵守NSCoder协议,因此它会为您处理转换。

+0

谢谢您的回答,我在写作的同时我自己的答案,所以我错过了你的。这将诀窍,虽然我真的需要存储PNG表示,因为iPhone SDK使用UIImage而不是NSImage。简单的无变压器解决方案适用于mac,但在iPhone上读取sqlite数据库时会中断。 – Gael 2010-05-22 08:24:29

+0

是的,我自己使用了一个自定义转换器,因为我想在将图像存储在核心数据中之前将图像大小调整为较小。我允许某人将图像拖到图像上,因此可能会添加大图像,并且我不想存储这么大的图像...因此我的变压器(尽管我删除了在张贴的变压器中调整大小的图像) 。 – regulus6633 2010-05-22 08:31:07