Last active
June 11, 2024 08:35
-
-
Save IanKeen/4d29b48519dca125b21675eeb7623d60 to your computer and use it in GitHub Desktop.
PropertyWrapper: Storage to extend support for more types using `@AppStorage`
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
// RawRepresentable types using Double aren't supported by default by AppStorage | |
enum Foo: Double, AppStorageConvertible { | |
case a = 1.0 | |
case b = 1.5 | |
} | |
struct MyView: View { | |
@AppStorage("foo") @Storage private var foo: Foo = .a | |
var body: some View { | |
Text("\(foo.rawValue)") | |
Button("A") { foo = .a } | |
Button("B") { foo = .b } | |
} | |
} |
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
struct MyView: View { | |
// [String] isn't supported by default by AppStorage, `@Storage` supports it for free | |
@AppStorage("foo") @Storage private var foo: [String] = [] | |
var body: some View { | |
Text(foos.joined(separator: ",")) | |
Button("A") { foos.append("A") } | |
Button("B") { foos.append("b") } | |
} | |
} |
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
@propertyWrapper | |
struct Storage<T: AppStorageConvertible>: RawRepresentable { | |
var rawValue: String { wrappedValue.storedValue } | |
var wrappedValue: T | |
init?(rawValue: String) { | |
guard let value = T.init(rawValue) else { return nil } | |
self.wrappedValue = value | |
} | |
init(wrappedValue: T) { | |
self.wrappedValue = wrappedValue | |
} | |
} | |
extension Binding { | |
func binding<T>() -> Binding<T> where Value == Storage<T> { | |
return .init( | |
get: { wrappedValue.wrappedValue }, | |
set: { value, transaction in | |
self.transaction(transaction).wrappedValue.wrappedValue = value | |
} | |
) | |
} | |
} | |
protocol AppStorageConvertible { | |
init?(_ storedValue: String) | |
var storedValue: String { get } | |
} | |
extension RawRepresentable where RawValue: LosslessStringConvertible, Self: AppStorageConvertible { | |
init?(_ storedValue: String) { | |
guard let value = RawValue(storedValue) else { return nil } | |
self.init(rawValue: value) | |
} | |
var storedValue: String { | |
String(describing: rawValue) | |
} | |
} | |
extension Array: AppStorageConvertible where Element: LosslessStringConvertible { | |
public init?(_ storedValue: String) { | |
let values = storedValue.components(separatedBy: ",") | |
self = values.compactMap(Element.init) | |
} | |
var storedValue: String { | |
return map(\.description).joined(separator: ",") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment