Conforming to RawRepresentable the use of a NSKeyedArchiver

iOS 14 got here with some thrilling new options for SwiftUI and one of my favourites is the @AppStorage
wrapper. This new assets wrapper makes storing a price in UserDefaults
approach more uncomplicated. Prior to iOS 14, this could must be completed with through the use of getter and setter strategies.
(*5*)@AppStorage Documentation
The @AppStorage natively helps Bool
, Int
, String
, URL
& Data
. But what if you wish to show extra difficult information sorts? For instance, a SwiftUI Color
. I got here throughout this downside myself growing one of my very own apps. I sought after to retailer a default tint colour for positive content material in UserDefaults
, decided on the use of (additionally new with iOS 14) ColorPicker
.
(*16*)To fortify a non-primitive or customized elegance, you will have to lengthen the kind to adapt to RawRepresentable
. The protocol specifies each a customized initializer for initializing a price from a uncooked kind, and a public variable for changing an object example to the uncooked kind. To comply with this protocol, sadly we will’t use some of the extra complex sorts like Data
. We are restricted to the use of both a String
or Int
as our uncooked kind.
No topic, the use of an integer as a sort to retailer a colour is lovely commonplace and has been completed earlier than. Unfortunately, it’s now not as simple because it first appeared. My first concept was once to make use of a unmarried 64 Bit Integer to retailer the 4 colour elements as bytes within the following layout RRRRRRRR GGGGGGGG BBBBBBBB AAAAAAAA…
. To save to UserDefaults
, I might extract the colour elements from the SwiftUI Color
(By changing to CIColor
) and then shift the elements into the proper portions of the integer.
If you don’t know what bit moving is, right here’s a handy guide a rough rundown: https://en.wikipedia.org/wiki/Logical_shift
A 64 Bit Integer can natively be saved in UserDefaults
so your next step is to easily opposite the method and then reconstruct a brand new SwiftUI Color
object from the extracted elements when wanted. Tada! A sexy easy technique to convert and retailer a Color
as a primitive (and again). Here’s a handy guide a rough instance implementation.
(*8*)Converting to an Integer
let crimson = Int(coreImageColor.crimson * 255 + 0.5)
let inexperienced = Int(coreImageColor.inexperienced * 255 + 0.5)
let blue = Int(coreImageColor.blue * 255 + 0.5)
go back (crimson << 16) | (inexperienced << 8) | blue
Converting again to a Color
let crimson = Double((rawValue & 0xFF0000) >> 16) / 0xFF
let inexperienced = Double((rawValue & 0x00FF00) >> 8) / 0xFF
let blue = Double(rawValue & 0x0000FF) / 0xFF
self = Color(crimson: crimson, inexperienced: inexperienced, blue: blue)
Original Gist
(*14*)Unfortunately, It wasn’t that easy. Extracting to elements and again, ceaselessly brought about some floating level mistakes. 0 values would ceaselessly be represented as very small numbers which might lead to some very ordinary surprising conduct. I attempted vary locking the values (to 0 — 255) however I nonetheless were given some very ordinary UI Behaviour.