diff --git a/DefaultsKit.xcodeproj/project.pbxproj b/DefaultsKit.xcodeproj/project.pbxproj index 9be3085..6605134 100644 --- a/DefaultsKit.xcodeproj/project.pbxproj +++ b/DefaultsKit.xcodeproj/project.pbxproj @@ -11,6 +11,12 @@ A0AC4AAF1F43853D0070F91D /* DefaultsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0AC4AAE1F43853D0070F91D /* DefaultsTests.swift */; }; A0AC4AB11F43853D0070F91D /* DefaultsKit.h in Headers */ = {isa = PBXBuildFile; fileRef = A0AC4AA31F43853D0070F91D /* DefaultsKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; A0AC4ABB1F4385500070F91D /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0AC4ABA1F4385500070F91D /* Defaults.swift */; }; + A0DFDB0A20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */; }; + A0DFDB0B20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */; }; + A0DFDB0C20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */; }; + A0DFDB0E20CD8C58004A4C2F /* PersonMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */; }; + A0DFDB0F20CD8C58004A4C2F /* PersonMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */; }; + A0DFDB1020CD8C58004A4C2F /* PersonMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */; }; A0F000F61F48CEE500617715 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0AC4ABA1F4385500070F91D /* Defaults.swift */; }; A0F001041F48CF9D00617715 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0AC4ABA1F4385500070F91D /* Defaults.swift */; }; A0F0011E1F48D0BD00617715 /* DefaultsKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A0F000E91F48CECE00617715 /* DefaultsKit.framework */; }; @@ -51,6 +57,8 @@ A0AC4AAE1F43853D0070F91D /* DefaultsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsTests.swift; sourceTree = ""; }; A0AC4AB01F43853D0070F91D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A0AC4ABA1F4385500070F91D /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = ""; }; + A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DefaultsKey + keys.swift"; sourceTree = ""; }; + A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonMock.swift; sourceTree = ""; }; A0F000E91F48CECE00617715 /* DefaultsKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DefaultsKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A0F000FC1F48CF8200617715 /* DefaultsKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DefaultsKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A0F001191F48D0BD00617715 /* DefaultsKit macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "DefaultsKit macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -141,8 +149,10 @@ A0AC4AAD1F43853D0070F91D /* Tests */ = { isa = PBXGroup; children = ( + A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */, A0AC4AAE1F43853D0070F91D /* DefaultsTests.swift */, A0AC4AB01F43853D0070F91D /* Info.plist */, + A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */, ); path = Tests; sourceTree = ""; @@ -396,6 +406,8 @@ buildActionMask = 2147483647; files = ( A0AC4AAF1F43853D0070F91D /* DefaultsTests.swift in Sources */, + A0DFDB0A20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */, + A0DFDB0E20CD8C58004A4C2F /* PersonMock.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -420,6 +432,8 @@ buildActionMask = 2147483647; files = ( A0F001271F48D12900617715 /* DefaultsTests.swift in Sources */, + A0DFDB0C20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */, + A0DFDB1020CD8C58004A4C2F /* PersonMock.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -428,6 +442,8 @@ buildActionMask = 2147483647; files = ( A0F001381F48D35700617715 /* DefaultsTests.swift in Sources */, + A0DFDB0B20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */, + A0DFDB0F20CD8C58004A4C2F /* PersonMock.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/README.md b/README.md index 9a563c4..753fe86 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,20 @@ if defaults.has(key) { ``` > If you just need to know that a key/value pair exists, **without actually using the value**, use the `has()` method instead of the optional `get(for:key)`. For complex objects it will prevent any unnecessary deserialization. +### Implicit Member Expression + +You can find a convenience wrapper for your keys by extending `DefaultsKey`. This allows you use [Implicit Member Expression](https://docs.swift.org/swift-book/ReferenceManual/Expressions.html#//appleref/swift/grammar/implicit-member-expression): +```swift +// Extend with a custom key +extension DefaultsKey { + static let someKey = Key("someKey") +} + +// Then use it like this +defaults.set("Some key", for: .someKey) +defaults.get(for: .someKey) // Output: Some key +``` + ### Complex objects To store a complex object just conform to the [Codable](https://developer.apple.com/documentation/swift/codable) protocol: diff --git a/Sources/Defaults.swift b/Sources/Defaults.swift index c94c276..a096285 100644 --- a/Sources/Defaults.swift +++ b/Sources/Defaults.swift @@ -24,11 +24,13 @@ import Foundation +public class DefaultsKey {} + /// Represents a `Key` with an associated generic value type conforming to the /// `Codable` protocol. /// /// static let someKey = Key("someKey") -public final class Key { +public final class Key: DefaultsKey { fileprivate let _key: String public init(_ key: String) { _key = key diff --git a/Tests/DefaultsKey + keys.swift b/Tests/DefaultsKey + keys.swift new file mode 100644 index 0000000..b96e8c5 --- /dev/null +++ b/Tests/DefaultsKey + keys.swift @@ -0,0 +1,21 @@ +// +// DefaultsKey + keys.swift +// DefaultsKit +// +// Created by Nuno Dias on 10/06/2018. +// Copyright © 2018 Nuno Dias. All rights reserved. +// + +import Foundation +@testable import DefaultsKit + +extension DefaultsKey { + static let integerKey = Key("integerKey") + static let floatKey = Key("floatKey") + static let doubleKey = Key("doubleKey") + static let stringKey = Key("stringKey") + static let boolKey = Key("boolKey") + static let dateKey = Key("dateKey") + static let arrayOfIntegersKey = Key<[Int]>("arrayOfIntegersKey") + static let personMockKey = Key("personMockKey") +} diff --git a/Tests/DefaultsTests.swift b/Tests/DefaultsTests.swift index 0d64aae..1dda917 100644 --- a/Tests/DefaultsTests.swift +++ b/Tests/DefaultsTests.swift @@ -43,16 +43,15 @@ class DefaultsKitTests: XCTestCase { // Given let value = 123 - let key = Key("key") // When - defaults.set(value, for: key) + defaults.set(value, for: .integerKey) // Then - let hasKey = defaults.has(key) + let hasKey = defaults.has(.integerKey) XCTAssertTrue(hasKey) - let savedValue = defaults.get(for: key) + let savedValue = defaults.get(for: .integerKey) XCTAssertEqual(savedValue, value) } @@ -61,16 +60,15 @@ class DefaultsKitTests: XCTestCase { // Given let value: Float = 123.1 - let key = Key("key") // When - defaults.set(value, for: key) + defaults.set(value, for: .floatKey) // Then - let hasKey = defaults.has(key) + let hasKey = defaults.has(.floatKey) XCTAssertTrue(hasKey) - let savedValue = defaults.get(for: key) + let savedValue = defaults.get(for: .floatKey) XCTAssertEqual(savedValue, value) } @@ -79,16 +77,15 @@ class DefaultsKitTests: XCTestCase { // Given let value: Double = 123.1 - let key = Key("key") // When - defaults.set(value, for: key) + defaults.set(value, for: .doubleKey) // Then - let hasKey = defaults.has(key) + let hasKey = defaults.has(.doubleKey) XCTAssertTrue(hasKey) - let savedValue = defaults.get(for: key) + let savedValue = defaults.get(for: .doubleKey) XCTAssertEqual(savedValue, value) } @@ -97,16 +94,15 @@ class DefaultsKitTests: XCTestCase { // Given let value = "a string" - let key = Key("key") // When - defaults.set(value, for: key) + defaults.set(value, for: .stringKey) // Then - let hasKey = defaults.has(key) + let hasKey = defaults.has(.stringKey) XCTAssertTrue(hasKey) - let savedValue = defaults.get(for: key) + let savedValue = defaults.get(for: .stringKey) XCTAssertEqual(savedValue, value) } @@ -115,16 +111,15 @@ class DefaultsKitTests: XCTestCase { // Given let value = true - let key = Key("key") // When - defaults.set(value, for: key) + defaults.set(value, for: .boolKey) // Then - let hasKey = defaults.has(key) + let hasKey = defaults.has(.boolKey) XCTAssertTrue(hasKey) - let savedValue = defaults.get(for: key) + let savedValue = defaults.get(for: .boolKey) XCTAssertEqual(savedValue, value) } @@ -133,16 +128,15 @@ class DefaultsKitTests: XCTestCase { // Given let value = Date() - let key = Key("key") // When - defaults.set(value, for: key) + defaults.set(value, for: .dateKey) // Then - let hasKey = defaults.has(key) + let hasKey = defaults.has(.dateKey) XCTAssertTrue(hasKey) - let savedValue = defaults.get(for: key) + let savedValue = defaults.get(for: .dateKey) XCTAssertEqual(savedValue, value) } @@ -151,16 +145,15 @@ class DefaultsKitTests: XCTestCase { // Given let values = [1,2,3,4] - let key = Key<[Int]>("key") // When - defaults.set(values, for: key) + defaults.set(values, for: .arrayOfIntegersKey) // Then - let hasKey = defaults.has(key) + let hasKey = defaults.has(.arrayOfIntegersKey) XCTAssertTrue(hasKey) - let savedValues = defaults.get(for: key) + let savedValues = defaults.get(for: .arrayOfIntegersKey) XCTAssertNotNil(savedValues) savedValues?.forEach({ (value) in XCTAssertTrue(savedValues?.contains(value) ?? false) @@ -172,43 +165,34 @@ class DefaultsKitTests: XCTestCase { // Given let values = [1,2,3,4] - let key = Key<[Int]>("key") // When - defaults.set(values, for: key) - defaults.clear(key) + defaults.set(values, for: .arrayOfIntegersKey) + defaults.clear(.arrayOfIntegersKey) // Then - let hasKey = defaults.has(key) + let hasKey = defaults.has(.arrayOfIntegersKey) XCTAssertFalse(hasKey) - let savedValues = defaults.get(for: key) + let savedValues = defaults.get(for: .arrayOfIntegersKey) XCTAssertNil(savedValues) } func testSetObject() { - // Mocks - struct PersonMock: Codable { - let name: String - let age: Int - let children: [PersonMock] - } - // Given let child = PersonMock(name: "Anne Greenwell", age: 30, children: []) let person = PersonMock(name: "Bonnie Greenwell", age: 80, children: [child]) - let key = Key("personKey") // When - defaults.set(person, for: key) + defaults.set(person, for: .personMockKey) // Then - let hasKey = defaults.has(key) + let hasKey = defaults.has(.personMockKey) XCTAssertTrue(hasKey) - let savedPerson = defaults.get(for: key) + let savedPerson = defaults.get(for: .personMockKey) XCTAssertEqual(savedPerson?.name, "Bonnie Greenwell") XCTAssertEqual(savedPerson?.age, 80) XCTAssertEqual(savedPerson?.children.first?.name, "Anne Greenwell") diff --git a/Tests/PersonMock.swift b/Tests/PersonMock.swift new file mode 100644 index 0000000..5f8b977 --- /dev/null +++ b/Tests/PersonMock.swift @@ -0,0 +1,15 @@ +// +// PersonMock.swift +// DefaultsKit +// +// Created by Nuno Dias on 10/06/2018. +// Copyright © 2018 Nuno Dias. All rights reserved. +// + +import Foundation + +struct PersonMock: Codable { + let name: String + let age: Int + let children: [PersonMock] +}