Did anyone successfully used transformable in SwiftData to store UIColor or SwiftUI Color type?
@Attribute(.transformable) var color: UIColor
Did anyone successfully used transformable in SwiftData to store UIColor or SwiftUI Color type?
@Attribute(.transformable) var color: UIColor
I made .transformable
work this way, but there is - probably/hopefully - better solution as this looks ugly.
import SwiftUI
import SwiftData
@Model
final class MyModel {
// ...
@Attribute(.transformable) var color: Color {
get {
_$observationRegistrar.access(self, keyPath: \.hexColor)
return Color(hex: self.getValue(for: \.hexColor))
}
set {
_$observationRegistrar.withMutation(of: self, keyPath: \.hexColor) {
self.setValue(for: \.hexColor, to: newValue.hex)
}
}
}
// ...
}
And here is the extension.
import SwiftData
import SwiftUI
import UIKit
extension Color {
var hex: UInt {
let components = self.cgColor?.components
let r = components?[0] ?? 0
let g = components?[1] ?? 0
let b = components?[2] ?? 0
let red = UInt(r * 255) << 16
let green = UInt(g * 255) << 08
let blue = UInt(b * 255)
return red | green | blue
}
init(hex: UInt, alpha: Double = 1) {
self.init(
.sRGB,
red: Double((hex >> 16) & 0xff) / 255,
green: Double((hex >> 08) & 0xff) / 255,
blue: Double((hex >> 00) & 0xff) / 255,
opacity: alpha
)
}
}
I missed required property.
var hexColor: UInt
Thanks!
I agree! There has to be a better way. Since if I am using hexColor then I can simply save hexColor in the database or hex code and construct Color from that. I think we have to somehow make Color or UIColor conform to codable.
It is probably a bad idea to try to store a UI type in the model. It would be better to store a model type in the model and then transform it into a UI type using the SwiftUI View
hierarchy, i.e. using a computed property called from body
that returns a Color
struct created from the model type.
It's now possible to use transformable(by:)
.
@Model
final class Profile {
@Attribute(.unique) let id: UUID
var name: String
@Attribute(.transformable(by: UIColorValueTransformer.self)) var uiColor: UIColor
var color: Color {
get {
.init(uiColor: uiColor)
}
set {
uiColor = .init(newValue)
}
}
init(id: UUID = UUID(), name: String, color: Color) {
self.id = id
self.name = name
self.uiColor = .init(color)
}
}
@main
struct MyApp: App {
init() {
UIColorValueTransformer.register()
}
}
The transformer code can be found here: https://www.avanderlee.com/swift/valuetransformer-core-data/