核心数据数据模型:UIColor的属性类型

时间:2010-02-21 05:19:50

标签: iphone objective-c cocoa-touch core-data

我刚开始使用Core Data,现在我正在构建我的数据模型。我的实体需要一个UIColor属性,但属性的类型下拉列表没有这个选项。我将它设置为Undefined还是什么?

由于

5 个答案:

答案 0 :(得分:20)

我将解释我在Dave Mark和Jeff LeMarche的更多iPhone 3开发中找到的明确答案:

通常我们可以将transformable属性的变换器类保留为默认值 NSKeyedUnarchiveFromData 并完成,但在这种情况下我们不能因为UIColor不符合NSCoding ,无法使用NSKeyedArchiver归档。我们必须手动编写一个值转换器来处理转换。

向您的实体添加属性并调用属性“color”或您希望的任何名称。将其类型设置为 Transformable 。将其“值转换器名称”设置为 UIColorRGBValueTransformer 。请注意,数据模型编辑器不验证值转换器名称:以确保它是有效的类,因此请仔细键入。

创建一个新文件,NSObject的子类,并将其命名为 UIColorRGBValueTransformer.m

单击 UIColorRGBValueTransformer.h 并将超类从NSObject更改为NSValueTransformer。另外,将#import <Foundation/Foundation.h>更改为#import <UIKit/UIKit.h>,因为UIColor属于UIKit,而非Foundation

现在在 UIColorRGBValueTransformer.m 中,我们需要实现四种方法,允许我们的值转换器类将UIColor的实例转换为NSData,反之亦然。在 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

现在在另一个文件中,您可以添加一行代码,如:

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

无需在文件中导入 UIColorRGBValueTransformer.h

答案 1 :(得分:16)

您可能需要的是可转换属性。另请参阅“核心数据编程指南”中有关“Non-standard Persistent Attributes”的部分。可转换属性在底层下面是二进制数据属性,但Core Data将自动使用规范的NSValueTransformer来为您序列化和反序列化逻辑属性值。对于符合NSCoding的值,NSKeyedUnarchiveFromDataTransformerName(默认变换器)将起到作用。

当然,Core Data无法索引,或者对于SQLite后端,无法对此可转换值进行查询。

答案 2 :(得分:3)

是否可以将UIColor作为字符串存储为HEX(FFFFFF或其他网页安全颜色),然后当您阅读颜色时,将字符串转换为UIColor可以理解的格式?

答案 3 :(得分:3)

将颜色属性指定为可变形,名称为ColorToDataTransformer。 我们可以简单地生成MangatedObjectSubclass并在其中编写转换器代码

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

答案 4 :(得分:0)

这里是@RosePerrone答案的Swift版本。 希望对您有所帮助。

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)
}

}