Хранить UIColor в CoreData

Как я могу хранить UIColor в CoreData без потерь на 64 бит? На 32 бит возвращается правильный UIColor.

Настройка CoreData

  • тип атрибута: трансформируемый
  • Свойство подкласса NSManagedObject: @NSManaged var color: UIColor?

Перед сохранением значения цвета

color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)

например, красный на 64-битной:

0.20000000000000018  

красный вывод на 32 бит

0.199999928

После того, как цвет получен из CoreData

color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)

например, красный на 64-битной:

0.20000000298023224 

красный вывод на 32 бит:

0.199999928

Результирующая проблема

Сравнение цветов с использованием == завершается неудачно на 64-битной, потому что значения немного отличаются. На 32-битной все хорошо, и сравнение цветов успешно.

3 ответа

Приписывать NSKeyedArchiver.archivedDataWithRootObject(color) в переменную данных и сохраните ее в хранилище Core Data.

Чтобы прочитать данные, просто назначьте NSKeyedUnarchiver.unarchiveObjectWithData(colorData) в цветовую переменную.


Если вам интересно, как сравнить поплавки, вы всегда можете обратиться к этому.

Это решило мою проблему:

  1. установить имя атрибута CoreData для моего пользовательского подкласса NSValueTransformer: MQColorTransformer

  2. реализовал следующий подкласс NSValueTransformer (который также преобразует UIColor в NSData, как предложил Schemetrical, но у него есть преимущество в том, что я все еще могу назначить UIColor своему свойству цвета, а NSValueTransformer позаботится о преобразовании за кулисами):

NSValueTransformer подкласс

import Foundation
import UIKit

@objc(MQColorTransformer) class MQColorTransformer: NSValueTransformer {

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

  override func transformedValue(value: AnyObject!) -> AnyObject {

      // Transform UIColor to NSData
      let color = value as! UIColor

      var red: CGFloat = 0
      var green: CGFloat = 0
      var blue: CGFloat = 0
      var alpha: CGFloat = 0
      color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)

      var components:[CGFloat] = [red, green, blue, alpha]
      let dataFromColors = NSData(bytes: components,
          length: sizeofValue(components)*components.count)

      return dataFromColors

  }

  override func reverseTransformedValue(value: AnyObject!) -> AnyObject {

      // Transform NSData to UIColor
      let data = value  as! NSData
      var components = [CGFloat](count: 4, repeatedValue:0)
      var length=sizeofValue(components)

      data.getBytes(&components, length: length * components.count)
      let color = UIColor(red: components[0],
          green: components[1],
          blue: components[2],
          alpha: components[3])

      return color
  }
}

Swift 5.7, минимальная цель развертывания iOS 11

      import UIKit

final class ColorAttributeTransformer: ValueTransformer {
    override class func transformedValueClass() -> AnyClass {
        NSData.self
    }
    
    override func transformedValue(_ value: Any?) -> Any? {
        let color = value as! UIColor
        
        return NSKeyedArchiver.archivedData(withRootObject: color)
    }
    
    override func reverseTransformedValue(_ value: Any?) -> Any? {
        let data = value as! Data

        return NSKeyedUnarchiver.unarchiveObject(with: data)
    }
}

Имейте в виду, что Xcode выполняет в консоли:'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release.

Другие вопросы по тегам