CoreCode
CoreCode

Reputation: 2227

Store a NSColor as a string

I currently have a Core Data database that stores data and I wish to also store an NSColor into it but It does not accept NSColor as an object. My solution would be to store it as a string in the database and have it read into a NSColor when loaded. How would I do this?

For example, If I had a colour like [NSColor redColor] how would I store it in a database (as a string) and then retrieve it. This is a basic example and it would be more complicated RGB colors in the end.

Thanks.

Upvotes: 0

Views: 2774

Answers (5)

Jeff
Jeff

Reputation: 2699

Here are simple functions for converting an NSColor to and from an NSString. This example assumes we're using an RGB color space, but it can be easily adapted for others. For example, NSStringFromColor() could include the color space in the string and use that information when converting back to a color in NSColorFromString().

Usage:

NSString *theColorString = NSStringFromColor(theColor);
NSColor *theColor = NSColorFromString(theColorString);

The functions:

NSString *NSStringFromColor(NSColor *theColor)
{
    CGFloat red, green, blue, alpha;
    [theColor getRed:&red green:&green blue:&blue alpha:&alpha]; // assumes RGB color space
    NSString *theColorString = [NSString stringWithFormat:@"%f %f %f %f",red,green,blue,alpha];
    return theColorString;
}

NSColor *NSColorFromString(NSString *theColorString)
{
    if ( theColorString.length == 0 ) {
        theColorString = @"0.9 0.9 0.95 1.0"; // a default color
    }
    NSArray <NSString *> *theColors = [theColorString componentsSeparatedByString:@" "];
    if ( theColors.count == 4 ) { // sanity
        // unpack the color
        NSColor *theColor = [NSColor colorWithSRGBRed:theColors[0].floatValue
                                                green:theColors[1].floatValue
                                                 blue:theColors[2].floatValue
                                                alpha:theColors[3].floatValue];
        return theColor;
    }
    return nil; // theColorString format error
}

Upvotes: 0

Caleb
Caleb

Reputation: 125037

I agree with the answers that recommend using NSData for storing colors in a Core Data store. That said, there may be times when it might be useful to store a color in a string, and it's certainly not difficult to do. I'd suggest creating a category on NSColor:

@interface NSColor (NSString)
- (NSString*)stringRepresentation;
+ (NSColor*)colorFromString:(NSString*)string forColorSpace:(NSColorSpace*)colorSpace;
@end

@implementation NSColor (NSString)

- (NSString*)stringRepresentation
{
    CGFloat components[10];

    [self getComponents:components];
    NSMutableString *string = [NSMutableString string];
    for (int i = 0; i < [self numberOfComponents]; i++) {
        [string appendFormat:@"%f ", components[i]];
    }
    [string deleteCharactersInRange:NSMakeRange([string length]-1, 1)]; // trim the trailing space
    return string;
}

+ (NSColor*)colorFromString:(NSString*)string forColorSpace:(NSColorSpace*)colorSpace
{
    CGFloat components[10];    // doubt any color spaces need more than 10 components
    NSArray *componentStrings = [string componentsSeparatedByString:@" "];
    int count = [componentStrings count];
    NSColor *color = nil;
    if (count <= 10) {
        for (int i = 0; i < count; i++) {
            components[i] = [[componentStrings objectAtIndex:i] floatValue];
        }
        color = [NSColor colorWithColorSpace:colorSpace components:components count:count];
    }
    return color;
}

@end

I've checked that the code above compiles and works about as advertised. A small sample program produces appropriate output:

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSLog(@"Red is: %@", [[NSColor redColor] stringRepresentation]);
        NSLog(@"Cyan is: %@", [[NSColor cyanColor] stringRepresentation]);
        NSLog(@"Read in: %@", [NSColor colorFromString:[[NSColor redColor] stringRepresentation]
                                         forColorSpace:[NSColorSpace deviceRGBColorSpace]]);
    }
    return 0;
}

Output:

Red is: 1.000000 0.000000 0.000000 1.000000
Cyan is: 0.000000 1.000000 1.000000 1.000000
Read in: NSCustomColorSpace Generic RGB colorspace 1 0 0 1

It might make sense to store the color space in the string so you don't have to specify it when you go from string to color. Then again, if you're just going to store these strings and read them again, you should be using NSData anyway. Using strings makes more sense if you need to write colors into some sort of human-readable file, or perhaps as a debugging aid.

Upvotes: 3

CRD
CRD

Reputation: 53010

Property lists do not store colors and Apple recommends you store them as NSData not as NSString, you should probably do the same. See Apple's instructions here.

Upvotes: 0

voromax
voromax

Reputation: 3389

You should consider using NSData as container for storing unsupported data types in Core Data. To access NSColor as NSData you will need to mark attribute as transformable and create reversible NSValueTransformer class to transform NSColor as NSData.

Useful Link: Non-Standard Persistent Attributes

Upvotes: 4

Adam Rosenfield
Adam Rosenfield

Reputation: 400642

NSColor supports the NSCoding protocol, so you can use the -encodeWithCoder: method to save it to an archive, and you can use -initWithCoder: to load it from an archive.

Upvotes: 2

Related Questions