Why is my transformable Core Data attribute not using my custom NSValueTransformer?

后端 未结 6 604
故里飘歌
故里飘歌 2020-11-27 17:08

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.<

相关标签:
6条回答
  • 2020-11-27 17:43

    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.

    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.

    0 讨论(0)
  • 2020-11-27 17:49

    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.

    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.

    0 讨论(0)
  • 2020-11-27 17:51

    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.

    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.

    0 讨论(0)
  • 2020-11-27 17:55

    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

    + (void)initialize {
        if (self == [Event class]) {
            UIImageToDataTransformer *transformer = [[UIImageToDataTransformer alloc] init];
            [NSValueTransformer setValueTransformer:transformer forName:@"UIImageToDataTransformer"];
        }
    }
    
    0 讨论(0)
  • 2020-11-27 17:58

    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:

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

    0 讨论(0)
  • 2020-11-27 18:05

    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];
    }
    
    0 讨论(0)
提交回复
热议问题