Core Data data model: attribute type for UIColor

我的梦境 提交于 2019-12-29 04:53:53

问题


I'm just starting out with Core Data and right now I'm building my data model. I need a UIColor attribute for my entity, but the type dropdown for the attribute doesn't have an option for this. Do I set it to Undefined or what?

Thanks


回答1:


What you probably want is a transformable attribute. Give the section on "Non-standard Persistent Attributes" in the Core Data Programming Guide an other read. A transformable attribute is, underneath the covers, a binary data attribute, but Core Data will automatically use the NSValueTransformer of your specification to serialize and unserialize the logical attribute value for you. For values that are NSCoding compliant, the NSKeyedUnarchiveFromDataTransformerName (which is the default transformer) will do the trick.

Of course, Core Data cannot index or, for an SQLite backend, query against this transformable value.




回答2:


I'll paraphrase the definitve answer I found in More iPhone 3 Development by Dave Mark and Jeff LeMarche:

Usually we'd be able to leave the transformable attribute's transformer class as the default, NSKeyedUnarchiveFromData, and be done, but in this case we can't because UIColor doesn't conform to NSCoding and can't be archived using an NSKeyedArchiver. We have to manually write a value transformer to handle the transformation.

Add an attribute to your entity and call the attribute "color", or whatever name you wish. Set its type to Transformable. Set its "Value Transformer Name" to UIColorRGBValueTransformer. Note that the data model editor doesn't validate the Value Transformer Name: to make sure it's a valid class, so type carefully.

Create a new file, a subclass of NSObject, and name it UIColorRGBValueTransformer.m.

Click UIColorRGBValueTransformer.h and change the superclass from NSObject to NSValueTransformer. Also, change #import <Foundation/Foundation.h> to #import <UIKit/UIKit.h>, since UIColor is part of UIKit, not Foundation.

Now in UIColorRGBValueTransformer.m, we need to implement four methods that allow our value transformer class to convert instances of UIColor to NSData and vice versa. Include the following code in UIColorRGBValueTransformer.m:

#import "UIColorRGBValueTransformer.h"

@implementation UIColorRGBValueTransformer

// Here we override the method that returns the class of objects that this transformer can convert.
+ (Class)transformedValueClass {
    return [NSData class];
}

// Here we indicate that our converter supports two-way conversions.
// That is, we need  to convert UICOLOR to an instance of NSData and back from an instance of NSData to an instance of UIColor.
// Otherwise, we wouldn't be able to beth save and retrieve values from the persistent store.
+ (BOOL)allowsReversTransformation {
    return YES;
}

// Takes a UIColor, returns an NSData
- (id)transfomedValue:(id)value {
    UIColor *color = value;
    const CGFloat *components = CGColorGetComponents(color.CGColor);
    NSString *colorAsString = [NSString stringWithFormat:@"%f,%f,%f,%f", components[0], components[1], components[2], components[3]];
    return [colorAsString dataUsingEncoding:NSUTF8StringEncoding];
}

// Takes an NSData, returns a UIColor
- (id)reverseTransformedValue:(id)value {
    NSString *colorAsString = [[[NSString alloc] initWithData:value encoding:NSUTF8StringEncoding] autorelease];
    NSArray *components = [colorAsString componentsSeparatedByString:@","];
    CGFloat r = [[components objectAtIndex:0] floatValue];
    CGFloat g = [[components objectAtIndex:1] floatValue];
    CGFloat b = [[components objectAtIndex:2] floatValue];
    CGFloat a = [[components objectAtIndex:3] floatValue];
    return [UIColor colorWithRed:r green:g blue:b alpha:a];
}

@end

Now in another file, you can include a line of code like:

[self.managedObject setValue:color forKey:self.keyPath];

without needing to import UIColorRGBValueTransformer.h in the file.




回答3:


Is it possible to store the UIColor as a String as a HEX (FFFFFF, or other web-safe colors) and then when you come to read the color, you convert the string into a format that UIColor can understand?




回答4:


After specify color attribute as transformable with name ColorToDataTransformer. We can simply generate MangatedObjectSubclass and write transformer code inside it

//SampleEntity.h

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface SampleEntity : NSManagedObject
@property (nonatomic, retain) UIColor *color;
@end

@interface ColorToDataTransformer : NSValueTransformer
@end

//SampleEntity.m

#import "SampleEntity.h"

@implementation SampleEntity

@dynamic color;

@end

@implementation ColorToDataTransformer

+ (BOOL)allowsReverseTransformation {
    return YES;
}

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


- (id)transformedValue:(id)value {
    UIColor *color = (UIColor *)value;
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:color];
    return data;
}

- (id)reverseTransformedValue:(id)value {
    NSData *data = (NSData *)value;
    UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    return color;
}

@end



回答5:


Here it is a Swift's Version of @RosePerrone answers. I Hope it helps.

class ColorToDataTransformer: ValueTransformer {

// Here we indicate that our converter supports two-way conversions.
// That is, we need  to convert UICOLOR to an instance of NSData and back from an instance of NSData to an instance of UIColor.
// Otherwise, we wouldn't be able to beth save and retrieve values from the persistent store.
override class func allowsReverseTransformation() -> Bool {
    return true
}

override class func transformedValueClass() -> AnyClass {
    return NSData.self
}

// Takes a UIColor, returns an NSData
override func transformedValue(_ value: Any?) -> Any? {
    guard let color = value as? UIColor else { return nil }

    guard let components: [CGFloat] = color.cgColor.components else { return nil }

    let colorAsString: String = String(format: "%f,%f,%f,%f", components[0], components[1], components[2], components[3])

    return colorAsString.data(using: .utf8)
}

// Takes an NSData, returns a UIColor
override func reverseTransformedValue(_ value: Any?) -> Any? {
    guard let data = value as? Data else { return nil }

    guard let colorAsString = String(data: data, encoding: .utf8) else { return nil }

    let componets: [String] = colorAsString.components(separatedBy: ",")

    var values: [Float] = []

    for component in componets {
        guard let value = Float(component) else { return nil }
        values.append(value)
    }

    let red: CGFloat = CGFloat(values[0])
    let green: CGFloat = CGFloat(values[1])
    let blue: CGFloat = CGFloat(values[2])
    let alpha: CGFloat = CGFloat(values[3])

   return UIColor(red: red, green: green, blue: blue, alpha: alpha)
}

}



来源:https://stackoverflow.com/questions/2304882/core-data-data-model-attribute-type-for-uicolor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!