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
Fire up Xcode and create a new project based on the iOS > Single View App template. Name the project Colors and set Language to Swift. To save us some time, we also check Use Core Data at the bottom. Save the project and select the data model of the project, Colors.
You can think of attributes as the columns of a table in a database. Attributes store the values of a Core Data record. There are several types of attributes, such as String, Date, Integer, Float, and Boolean. Select the Note entity in the data model editor and click the + button at the bottom of the Attributes table.
Core Data provides different attributes, including those common for all databases, such as Date or Decimal type, and non-standard attributes handled with Transformable type. It also provides Transient and Derived attributes so apps can derive one piece of data from the other.
When you declare a property as Transformable Core Data converts your custom data type into binary Data when it is saved to the persistent store and converts it back to your custom data type when fetched from the store. It does this through a value transformer.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With