Created
September 4, 2024 18:42
-
-
Save Jiropole/7dc1c0469d0ee52224d2e825dcdffbd0 to your computer and use it in GitHub Desktop.
Support using an arbitrary Codable value with AppStorage, with syntactic sugar to avoid referring directly to wrapped value.
This file contains hidden or 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
| // | |
| // AppStorageCodable.swift | |
| // | |
| // | |
| // Created by Jesse Hemingway on 9/4/24. | |
| // | |
| import Foundation | |
| import SwiftUI | |
| /** | |
| Support arbitrary Codable values with AppStorage, | |
| including syntactic sugar to avoid referring directly to wrapped value. | |
| Example usage: | |
| ``` | |
| struct ExampleStruct: Codable { | |
| var id: Int = 0 | |
| var name: String = "John" | |
| } | |
| class ExampleVendor: ObservableObject { | |
| @AppStorage("example") | |
| @AppStorageCodable | |
| var example: ExampleStruct = .init() | |
| } | |
| func testAppStorageCodable() { | |
| let exampleVendor = ExampleVendor() | |
| print("Example id: \(exampleVendor.example.id), name: \(exampleVendor.example.name)") | |
| } | |
| ``` | |
| */ | |
| @propertyWrapper | |
| @dynamicMemberLookup | |
| public struct AppStorageCodable<Value: Codable> { | |
| public var wrappedValue: Value | |
| public init(wrappedValue: Value) { | |
| self.wrappedValue = wrappedValue | |
| } | |
| subscript<T>(dynamicMember keyPath: WritableKeyPath<Value, T>) -> T { | |
| get { wrappedValue[keyPath: keyPath] } | |
| set { wrappedValue[keyPath: keyPath] = newValue } | |
| } | |
| } | |
| extension AppStorageCodable: RawRepresentable { | |
| public typealias RawValue = String | |
| public var rawValue: RawValue { | |
| guard let data = try? JSONEncoder().encode(wrappedValue), | |
| let string = String(data: data, encoding: .utf8) else { return "" } | |
| return string | |
| } | |
| public init?(rawValue: RawValue) { | |
| guard let data = rawValue.data(using: .utf8), | |
| let decoded = try? JSONDecoder().decode(Value.self, from: data) else { return nil } | |
| wrappedValue = decoded | |
| } | |
| } | |
| extension AppStorageCodable: Equatable where Value: Equatable {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment