objective-c 为什么我的可转换核心数据属性不使用我的自定义 NSValueTransformer?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1598600/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is my transformable Core Data attribute not using my custom NSValueTransformer?
提问by Rob Keniger
I have a Core Data app with a fairly simple data model. I want to be able to store instances of NSImage in the persistent store as PNG Bitmap NSData objects, to save space.
我有一个带有相当简单数据模型的 Core Data 应用程序。我希望能够将 NSImage 的实例作为 PNG Bitmap NSData 对象存储在持久存储中,以节省空间。
To this end, I wrote a simple NSValueTransformer to convert an NSImage to NSData in PNG bitmap format. I am registering the value transformer with this code in my App delegate:
为此,我编写了一个简单的 NSValueTransformer 将一个 NSImage 转换为 PNG 位图格式的 NSData。我正在我的应用程序委托中使用此代码注册值转换器:
+ (void)initialize
{
[NSValueTransformer setValueTransformer:[[PNGDataValueTransformer alloc] init] forName:@"PNGDataValueTransformer"];
}
In my data model, I have set the image attribute to be Transformable, and specified PNGDataValueTransformeras the value transformer name.
在我的数据模型中,我将图像属性设置为可转换,并指定PNGDataValueTransformer为值转换器名称。
However, my custom value transformer is not being used. I know this as I have placed log messages in my value transformer's -transformedValue:and -reverseTransformedValuemethods which are not being logged, and the data that is being saved to disk is just an archived NSImage, not the PNG NSData object that it should be.
但是,没有使用我的自定义值转换器。我知道这一点,因为我已经在我的值转换器-transformedValue:和-reverseTransformedValue方法中放置了没有被记录的日志消息,并且保存到磁盘的数据只是一个存档的 NSImage,而不是它应该是的 PNG NSData 对象。
Why is this not working?
为什么这不起作用?
Here is the code of my value transformer:
这是我的值转换器的代码:
@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
采纳答案by Rob Keniger
It turns out that this is actually a bug in the frameworks. See this post by an Apple employee on the Cocoa-Dev mailing list:
事实证明,这实际上是框架中的一个错误。请参阅 Cocoa-Dev 邮件列表上一位 Apple 员工的帖子:
http://lists.apple.com/archives/Cocoa-dev/2009/Dec/msg00979.html
http://lists.apple.com/archives/Cocoa-dev/2009/Dec/msg00979.html
回答by Brad Larson
If I'm not mistaken, your value transformer has a reversed direction. I do the same thing in my application, using code like the following:
如果我没记错的话,你的价值转换器有一个相反的方向。我在我的应用程序中做同样的事情,使用如下代码:
+ (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];
}
While this is for the iPhone, you should be able to swap in your NSImage code at the appropriate locations. I simply haven't tested my Mac implementation yet.
虽然这是针对 iPhone 的,但您应该能够在适当的位置交换 NSImage 代码。我只是还没有测试我的 Mac 实现。
All I did to enable this was to set my image property to be transformable within the data model, and specify the name of the transformer. I didn't need to manually register the value transformer, as you do in your +initialize method.
我所做的只是将我的图像属性设置为在数据模型中可转换,并指定转换器的名称。我不需要像在 +initialize 方法中那样手动注册值转换器。
回答by CornPuff
It seems registering the transformer has no effect on wether Core Data will use it or not. I've been playing with the PhotoLocations sample code and removing the transformer registration has no effect. As long as your ValueTransformerName is the name of your class, and that your transformer's implementation is included with the target, it should work.
注册变压器似乎对 Core Data 是否会使用它没有影响。我一直在玩 PhotoLocations 示例代码,删除变压器注册没有任何效果。只要您的 ValueTransformerName 是您的类的名称,并且您的转换器的实现包含在目标中,它就应该可以工作。
If there is no code execution in the transformer, then the code in the transformer is irrelevant. The problem must be somewhere else in the core data stack, or in the declaration of the transformer.
如果转换器中没有代码执行,那么转换器中的代码是无关紧要的。问题必须在核心数据堆栈中的其他地方,或者在转换器的声明中。
回答by Lukasz
You need to explicitly register your transformer during runtime.
您需要在运行时显式注册您的转换器。
Good place to do this is to override Class initialize method in your NSManagedObject entity subclass. As mentioned before it is known Core Data bug. Following is the crucial code from Apple's location code sample, it is tested and works: http://developer.apple.com/library/ios/#samplecode/Locations/Introduction/Intro.html
这样做的好地方是覆盖 NSManagedObject 实体子类中的类初始化方法。如前所述,它是已知的 Core Data 错误。以下是来自 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"];
}
}
回答by RyanJM
Check out the example code here.
在此处查看示例代码。
Does this do what you want?
这是你想要的吗?
@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];
}
回答by Brian Webster
If nothing in your code elsewhere explicity uses the PNGDataValueTransformer class, then the +initialize method for that class will never be called. Specifying the name in your Core Data model will not trigger it either - it will simply try looking up a value transformer for that name, which will return nil, since no transformer instance has yet been registered under that name.
如果其他地方的代码中没有任何内容明确使用 PNGDataValueTransformer 类,则永远不会调用该类的 +initialize 方法。在 Core Data 模型中指定名称也不会触发它 - 它只会尝试查找该名称的值转换器,该名称将返回 nil,因为尚未在该名称下注册转换器实例。
If this is indeed what's happening in your case, simply add a call to [PNGDataValueTransformer initialize] somewhere in your code before your data model gets accessed, e.g. in the +initialize method of whatever class it is that's using this data model. That should trigger the value transformer instance being created and registered so that Core Data can access it when it needs to.
如果这确实发生在您的情况下,只需在访问数据模型之前在代码中的某处添加对 [PNGDataValueTransformer initialize] 的调用,例如在使用此数据模型的任何类的 +initialize 方法中。这应该会触发正在创建和注册的值转换器实例,以便 Core Data 可以在需要时访问它。

