Last active
February 2, 2024 07:19
-
-
Save ericlewis/37fcd63cd04e03afe8e01f914e52d1fd to your computer and use it in GitHub Desktop.
Using Codable with AppStorage, the easy way!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import SwiftUI | |
// MARK: Demo | |
struct Example: RawRepresentable, Codable { | |
let id: UUID | |
} | |
// This is functionally the same as above, but we have a neater type without creating a new protocol. | |
typealias RawCodable = RawRepresentable & Codable | |
struct Example2: RawCodable { | |
let id: UUID | |
} | |
struct ContentView: View { | |
@AppStorage("1") | |
var first = [1] | |
@AppStorage("2") | |
var second = ["test": 123] | |
@AppStorage("3") | |
var third = Example(id: .init()) | |
var body: some View { | |
Text(first.description) | |
Text(second.description) | |
Text(third.id.description) | |
} | |
} | |
// MARK: General Codables | |
extension RawRepresentable where Self: Codable { | |
public init?(rawValue: String) { | |
guard let value: Self = Coders.encode(rawValue) else { return nil } | |
self = value | |
} | |
public var rawValue: String { | |
Coders.decode(self, default: "{}") | |
} | |
} | |
// MARK: Collections | |
// Slightly more complex than structs. | |
extension Collection where Self: RawRepresentable, Self: Codable, Element: Codable { | |
public var rawValue: String { | |
Coders.decode(self, default: "[]") | |
} | |
} | |
extension Array: RawRepresentable where Element: Codable { | |
public init?(rawValue: String) { | |
guard let value: Self = Coders.encode(rawValue) else { return nil } | |
self = value | |
} | |
} | |
extension Set: RawRepresentable where Element: Codable { | |
public init?(rawValue: String) { | |
guard let value: Self = Coders.encode(rawValue) else { return nil } | |
self = value | |
} | |
} | |
// MARK: Dictionary | |
extension Dictionary: RawRepresentable where Key: Codable, Value: Codable { | |
public init?(rawValue: String) { | |
guard let value: Self = Coders.encode(rawValue) else { return nil } | |
self = value | |
} | |
public var rawValue: String { | |
Coders.decode(self, default: "{}") | |
} | |
} | |
// MARK: Private Helpers | |
fileprivate struct Coders { | |
private static var _decoder: JSONDecoder { JSONDecoder() } | |
private static var _encoder: JSONEncoder { JSONEncoder() } | |
fileprivate static func encode<Value: Codable>(_ value: String) -> Value? { | |
guard let data = value.data(using: .utf8), let decoded = try? _decoder.decode(Value.self, from: data) else { | |
return nil | |
} | |
return decoded | |
} | |
fileprivate static func decode<Value: Codable>(_ value: Value, default: String) -> String { | |
guard let data = try? _encoder.encode(value), let value = String(data: data, encoding: .utf8) else { | |
return `default` | |
} | |
return value | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Bonus: skip all the raw representable stuff & just work with Codable types directly:
This code is obviously unsafe with all the force unwrapping, but it can be adjusted as needed!