diff --git a/Package.swift b/Package.swift index 8a61557..c45f04c 100644 --- a/Package.swift +++ b/Package.swift @@ -10,21 +10,24 @@ let package = Package( .macOS(.v11), .macCatalyst(.v14), .tvOS(.v14), - .watchOS(.v7) + .watchOS(.v7), ], products: [ // Products define the executables and libraries a package produces, making them visible to other packages. .library( name: "TypedAppStorage", - targets: ["TypedAppStorage"]), + targets: ["TypedAppStorage"] + ) ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products from dependencies. .target( - name: "TypedAppStorage"), + name: "TypedAppStorage" + ), .testTarget( name: "TypedAppStorageTests", - dependencies: ["TypedAppStorage"]), + dependencies: ["TypedAppStorage"] + ), ] ) diff --git a/Sources/TypedAppStorage/TypedAppStorage.swift b/Sources/TypedAppStorage/TypedAppStorage.swift index 062c8a7..97d241b 100644 --- a/Sources/TypedAppStorage/TypedAppStorage.swift +++ b/Sources/TypedAppStorage/TypedAppStorage.swift @@ -18,28 +18,36 @@ public protocol TypedAppStorageValue: Codable { public struct TypedAppStorage: DynamicProperty { private var appStorage: AppStorage private var initialValue: Value - + /// Store and fetch value from the defined store, with a predefined default value. /// /// This default value if defined is preferred over ``TypedAppStorageValue/defaultValue``. public init(wrappedValue: Value, store: UserDefaults? = nil) { initialValue = wrappedValue let initialData = try? JSONEncoder().encode(wrappedValue) - let initialString = (initialData == nil ? nil : String(data: initialData!, encoding: .utf8)) ?? "" - appStorage = .init(wrappedValue: initialString, Value.appStorageKey, store: store) + let initialString = + (initialData == nil ? nil : String(data: initialData!, encoding: .utf8)) + ?? "" + appStorage = .init( + wrappedValue: initialString, + Value.appStorageKey, + store: store + ) } - + /// Store and fetch value from the defined store. /// /// ``TypedAppStorageValue/defaultValue`` is used if no value was previously saved. public init(store: UserDefaults? = nil) { self.init(wrappedValue: Value.defaultValue, store: store) } - + /// The wrapped ``TypedAppStorageValue``. public var wrappedValue: Value { get { - guard let data = appStorage.wrappedValue.data(using: .utf8) else { return initialValue } + guard let data = appStorage.wrappedValue.data(using: .utf8) else { + return initialValue + } return (try? JSONDecoder().decode(Value.self, from: data)) ?? initialValue } nonmutating set { @@ -50,7 +58,7 @@ public struct TypedAppStorage: DynamicProperty { appStorage.wrappedValue = newString } } - + /// A two-way binding of ``wrappedValue``. public var projectedValue: Binding { .init { diff --git a/Tests/TypedAppStorageTests/TypedAppStorageTests.swift b/Tests/TypedAppStorageTests/TypedAppStorageTests.swift index 1b0b10d..c3be292 100644 --- a/Tests/TypedAppStorageTests/TypedAppStorageTests.swift +++ b/Tests/TypedAppStorageTests/TypedAppStorageTests.swift @@ -1,5 +1,6 @@ -import XCTest import SwiftUI +import XCTest + @testable import TypedAppStorage struct PreferredFruit: TypedAppStorageValue, Equatable { @@ -9,13 +10,13 @@ struct PreferredFruit: TypedAppStorageValue, Equatable { enum Freshness: Codable { case veryFresh, moderate, somewhatStale } - + static var appStorageKey = "preferredFruit" static var defaultValue = PreferredFruit(.veryFresh, .apple) - + var fruit: Fruit var freshness: Freshness - + init(_ freshness: Freshness, _ fruit: Fruit) { self.fruit = fruit self.freshness = freshness @@ -24,11 +25,11 @@ struct PreferredFruit: TypedAppStorageValue, Equatable { struct TestArticle: View { @TypedAppStorage var preferredFruit: PreferredFruit - + func changePreferred(to newValue: PreferredFruit) { preferredFruit = newValue } - + var body: some View { Text("Test") } @@ -36,11 +37,11 @@ struct TestArticle: View { struct TestArticleWithADifferentDefault: View { @TypedAppStorage var preferredFruit: PreferredFruit = .init(.moderate, .pear) - + func changePreferred(to newValue: PreferredFruit) { preferredFruit = newValue } - + var body: some View { Text("Test") } @@ -50,33 +51,36 @@ final class TypedAppStorageTests: XCTestCase { override func setUp() { UserDefaults.standard.removeObject(forKey: "preferredFruit") } - + func testReadDefaultValue() throws { let testArticle = TestArticle() - - XCTAssertEqual(testArticle.preferredFruit, PreferredFruit(.veryFresh, .apple)) + + XCTAssertEqual( + testArticle.preferredFruit, + PreferredFruit(.veryFresh, .apple) + ) } - + func testCallSiteDefault() throws { let testArticle = TestArticleWithADifferentDefault() - + XCTAssertEqual(testArticle.preferredFruit, .init(.moderate, .pear)) } - + func testSaveAndReadBack() throws { let testArticle = TestArticle() - + testArticle.changePreferred(to: .init(.somewhatStale, .banana)) - + XCTAssertEqual(testArticle.preferredFruit, .init(.somewhatStale, .banana)) } - + func testSaveAndReadElsewhere() throws { let articleA = TestArticle() let articleB = TestArticle() - + articleA.changePreferred(to: .init(.moderate, .banana)) - + XCTAssertEqual(articleB.preferredFruit, .init(.moderate, .banana)) } }