我正在尝试将PNG图像存储在由sqlite数据库支持的核心数据存储中。由于我打算在iPhone上使用此数据库,因此我无法直接存储NSImage
个对象。我想使用绑定和NSValueTransformer
子类来处理从NSImage
(由我的GUI上的图像井获得)到包含图像的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
。< / p>
可能有一些解决方法,例如this post中提到的解决方法,但我真的很想了解为什么我的方法存在缺陷。
提前感谢您的想法和解释。
答案 0 :(得分:1)
在transformedValue中:你直接从NSData转到NSImage但是在reverseTransformedValue中:你从NSImage转到NSBitmapImageRep转到NSData。所以这两者不能合作,因为他们使用不同的方法。模型中的数据实际上是NSBitmapImageRep数据,而不是NSImage数据。两者必须完全相反。
顺便说一句,我最近在另一篇文章中贴了一个变压器。你可以看到它here。当然,您根本不需要自定义变换器,因为您可以使用NSKeyedArchiver。 NSImage遵守NSCoder协议,因此它将为您处理转换。
答案 1 :(得分:1)
我最终得到了它的工作(最好睡觉)。有两个问题。第一个是我在IB绑定和核心数据模型中指定了相同的值转换器,这是多余的。
我的理解是IB绑定指定的值转换器实际上在视图和控制器之间转换值,而核心数据值转换器充当托管对象和持久存储之间的中间人。
更糟糕的是,第二个问题是我的价值转换器是倒置的。保存对象时发送transformValue
消息(托管对象 - >存储),并且在加载来自商店的值时发送reverseTransformedValue
,这与绑定时使用的变换器的方向相反查看对象来建模对象。我从core data programming guide得到了提示,你可以阅读以下有些神秘的说明:
重要说明:虽然默认变换器是NSKeyedUnarchiveFromDataTransformerName指定的变换器,但实际上反向使用此变换器。如果明确指定默认转换器,Core Data将“使用错误的方向”。
即使我的程序工作到目前为止,我希望得到具有核心数据经验的人的确认,如果您能指出我可能遗漏的一些文档,我将不胜感激。
提前致谢。
工作代码:
+ (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;
}