Swiftpack.co -  juliand665/UserDefault as Swift Package
Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
juliand665/UserDefault
Swifty User Defaults thanks to Property Wrappers
.package(url: "https://github.com/juliand665/UserDefault.git", from: "v1.0.1")

Swift Package Manager compatible MIT licensed

UserDefault

An overengineered property wrapper interface for UserDefaults.

This package started out as trying to write a property wrapper for accessing UserDefaults. However, it quickly grew beyond that as I wanted to avoid all the overhead of working with types that aren't directly property list convertible.

Example

Direct Storage

@UserDefault("hasSeenSplashScreen") var hasSeenSplashScreen = false
@UserDefault("name") var name: String?
@UserDefault("count") var count: Int? = 42

hasSeenSplashScreen = true
name = "John Appleseed"
count = nil

Codable/NSCoding

There's a protocol extensions for Codable that lets you avoid having to write that boilerplate yourself:

struct CodableStruct {
	var foo: String
}

extension CodableStruct: Equatable, Codable, DefaultsValueConvertible {}

@UserDefault("test") var test = CodableStruct(foo: "hello, world!")
test.foo = "goodbye."

As well as for NSCoding:

extension UIColor: DefaultsValueConvertible {}
@UserDefault("color") var color = UIColor.systemRed
color = .systemBlue

Further Conditional Conformances

I won't go into detail here, but there are also conditional conformances for Array, Dictionary, Collection, Optional, and RawRepresentable (making it easy to use enums). The goal is to cover all sensible cases in the standard library, so if you find something missing, please open an issue or PR!

Custom Conformance

You can either work directly with plist-compatible values:

struct Convertible {
	var name: String
}

extension Convertible: DefaultsValueConvertible {
	typealias DefaultsRepresentation = String
	
	init(defaultsRepresentation: String) throws {
		name = defaultsRepresentation
	}
	
	func defaultsRepresentation() throws -> String {
		name
	}
}

Or delegate that stuff to another type that conforms to DefaultsValueConvertible:

struct IndirectConvertible {
	var name: String
}

extension IndirectConvertible: IndirectDefaultsValueConvertible {
	typealias DefaultsRepresentation = Convertible.DefaultsRepresentation
	
	init(indirectRepresentation: Convertible) throws {
		name = indirectRepresentation.name
	}
	
	func indirectRepresentation() throws -> Convertible {
		try .init(defaultsRepresentation: name)
	}
}

Protocol Hierarchy

Plist-compatible types (like Bool, Data, String, etc.) conform to the DefaultsValue protocol, which establishes encoding to and from UserDefaults.

The @UserDefault property wrapper works with any type conforming to DefaultsValueConvertible, which encodes to and from an associated type that conforms to DefaultsValue, which is in turn stored in and loaded from the defaults. (DefaultsValue itself also conforms to this protocol so you can use it with the wrapper.)

If you'd like to delegate to another DefaultsValueConvertible type rather than working directly with plist-compatible types, you can instead conform to IndirectDefaultsValueConvertible (which inherits from the former), allowing you to encode to and from any DefaultsValueConvertible type. What this means is that you can have arbitrarily long chains of en-/decoding delegation with minimal boilerplate.

If you're working with a sequence-ish type, your best bet is probably to conform to ExpressibleByArray or ExpressibleBySequence, which will allow you to avoid the boilerplate of mapping your elements to/from their defaults representation provided you have a way to initialize yourself from an Array or any Sequence, respectively.

GitHub

link
Stars: 3
Last commit: 6 days ago

Ad: Job Offers

iOS Software Engineer @ Perry Street Software
Perry Street Software is Jack’d and SCRUFF. We are two of the world’s largest gay, bi, trans and queer social dating apps on iOS and Android. Our brands reach more than 20 million members worldwide so members can connect, meet and express themselves on a platform that prioritizes privacy and security. We invest heavily into SwiftUI and using Swift Packages to modularize the codebase.

Release Notes

Minor Fixes
10 weeks ago
  • Now compatible with tvOS and watchOS
  • Improvements to documentation & an actual readme
  • Operators now come from a package dependency rather than a file, fixing ambiguity issues when dependents had their own definitions for the same operators.

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API