{"id":13995222,"url":"https://github.com/AndrewBennet/PersistedPropertyWrapper","last_synced_at":"2025-07-22T21:32:18.357Z","repository":{"id":44734808,"uuid":"275011567","full_name":"AndrewBennet/PersistedPropertyWrapper","owner":"AndrewBennet","description":"A Swift library to enable easy persistent UserDefaults storage","archived":false,"fork":false,"pushed_at":"2024-11-22T21:48:02.000Z","size":97,"stargazers_count":40,"open_issues_count":2,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-22T22:32:09.778Z","etag":null,"topics":["cocoapods","ios","macos","property-wrapper","spm","swift","swift-library","userdefaults"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AndrewBennet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-25T20:44:28.000Z","updated_at":"2024-11-02T17:20:03.000Z","dependencies_parsed_at":"2024-11-06T21:25:20.465Z","dependency_job_id":"71345e74-4dd4-4789-94b6-cb897dcd8002","html_url":"https://github.com/AndrewBennet/PersistedPropertyWrapper","commit_stats":{"total_commits":40,"total_committers":3,"mean_commits":"13.333333333333334","dds":0.4,"last_synced_commit":"87f1b712aca5c5da3190470190afe9c4312c393e"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndrewBennet%2FPersistedPropertyWrapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndrewBennet%2FPersistedPropertyWrapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndrewBennet%2FPersistedPropertyWrapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndrewBennet%2FPersistedPropertyWrapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AndrewBennet","download_url":"https://codeload.github.com/AndrewBennet/PersistedPropertyWrapper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227177817,"owners_count":17743171,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cocoapods","ios","macos","property-wrapper","spm","swift","swift-library","userdefaults"],"created_at":"2024-08-09T14:03:18.746Z","updated_at":"2024-11-29T17:31:13.537Z","avatar_url":"https://github.com/AndrewBennet.png","language":"Swift","funding_links":[],"categories":["Swift"],"sub_categories":[],"readme":"# Persisted Property Wrapper\n![Swift](https://github.com/AndrewBennet/PersistedPropertyWrapper/workflows/Swift/badge.svg)\n![Swift Version](https://img.shields.io/badge/Swift-5.3-F16D39.svg?style=flat)\n![Cocoapods platforms](https://img.shields.io/cocoapods/p/PersistedPropertyWrapper)\n![GitHub](https://img.shields.io/github/license/AndrewBennet/PersistedPropertyWrapper)\n\n**Persisted Property Wrapper** is a Swift library to enable extremely easy persistance of variables in the [`UserDefaults`](https://developer.apple.com/documentation/foundation/userdefaults) database on Apple platforms.\n\nTo use **Persisted Property Wrapper** you simply annotate a variable as being `@Persisted`. It supports the standard `UserDefaults` types (`Int`, `String`, `Bool`, `Date` and more), along with `RawRepresentable` enums where the `RawValue` is storable in `UserDefaults`, as well as any type which conforms to `Codable` or `NSSecureCoding`. Plus of course any `Optional` wrapper of any of these types. The type-validity is checked at compile-time: attempting to use on any variables of a non-supported type will cause a compile-time error. \n\n## Usage\n\nStick a `@Persisted` attribute on your variable.\n\nThe first argument of the initializer is the string key under which the value will be stored in `UserDefaults`. If the type is non-Optional, you must also supply a `defaultValue`, which will be used when there is no value stored in `UserDefaults`.\n\nFor example:\n```swift\n@Persisted(\"UserSetting1\", defaultValue: 42)\nvar someUserSetting: Int\n\n@Persisted(\"UserSetting2\") // defaultValue not necessary since Int? is an Optional type\nvar someOtherUserSetting: Int?\n```\n\n### Storing Enums\nWant to store an enum value? If the enum has a backing type which is supported for storage in `UserDefaults`, then those can also be marked as `@Persisted`, and the actual value stored in `UserDefaults` will be the enum's raw value. For example:\n\n```swift\nenum AppTheme: Int {\n    case brightRed\n    case vibrantOrange\n    case plainBlue\n}\n\nstruct ThemeSettings {\n    // Stores the underlying integer backing the selected AppTheme\n    @Persisted(\"theme\", defaultValue: .plainBlue)\n    var selectedTheme: AppTheme\n}\n```\n\n### Storing Codable types\nAny codable type can be Persisted too; this will store in UserDefaults the JSON-encoded representation of the variable. For example:\n\n```swift\nstruct AppSettings: Codable {\n    var welcomeMessage = \"Hello world!\"\n    var isSpecialModeEnabled = false\n    var launchCount = 0\n\n    @Persisted(encodedDataKey: \"appSettings\", defaultValue: .init())\n    static var current: AppSettings\n}\n\n// Example usage: this will update the value of the stored AppSettings\nfunc appDidLaunch() {\n    AppSettings.current.launchCount += 1\n}\n```\n\nNote that the argument label `encodedDataKey` must be used. This is required to remove ambiguity about which storage method is used, since `UserDefaults`-storable types can be `Codable` too.\n\nFor example, the following two variables are stored via different mechanisms:\n```swift\n// Stores the integer in UserDefaults\n@Persisted(\"storedAsInteger\", defaultValue: 10)\nvar storedAsInteger: Int\n\n// Store the data of a JSON-encoded representation of the value. Don't use on iOS 12!\n@Persisted(encodedDataKey: \"storedAsData\", defaultValue: 10)\nvar storedAsData: Int\n```\n\n**Note:** on iOS 12, using the `encodedDataKey` initializer with a value which would encode to a JSON _fragment_ (e.g. `Int`, `String`, `Bool`, etc) will cause a crash. This is due to a [bug in the Swift runtime](https://bugs.swift.org/browse/SR-6163) shipped prior to iOS 13. Using `encodedDataKey` has no benefit in these cases anyway.\n\n### Storing types which implement `NSCoding`\nAny `NSObject` which conforms to `NSSecureCoding` can be Persisted too; this will store in UserDefaults the encoded representation of the object obtained from `NSKeyedArchiver`. For example:\n\n```swift\nclass CloudKitSyncManager {\n    @Persisted(archivedDataKey: \"ckServerChangeToken\")\n    var changeToken: CKServerChangeToken?\n}\n```\n\nNote that the argument label `archivedDataKey` must be used. As above, this is required to remove ambiguity about which storage method is used.\n\n**Note:** this storage mechanism is only supported on iOS 11 and up.\n\n### Alternative Storage\nBy default, a `@Persisted` property is stored in the `UserDefaults.standard` database; to store values in a different location, pass the `storage: ` parameter to the property wrapper:\n\n```swift\nextension UserDefaults {\n    static var alternative = UserDefaults(suiteName: \"alternative\")!\n}\n\n@Persisted(\"alternativeStoredValue\", storage: .alternative)\nvar alternativeStoredValue: Int?\n```\n\n## Why a Library?\nAfter all, there are lots of examples of similar utilities on the web. For example, [this post by John Sundell](https://www.swiftbysundell.com/articles/property-wrappers-in-swift/#a-propertys-properties) shows how a `@UserDefaultsBacked` property wrapper can be written in a handful of lines. \n\nHowever, during development of [my app](https://github.com/AndrewBennet/ReadingList), I found that I really wanted to store _enum values_ in `UserDefaults`. For any enum which is backed by integer or a string, there was an obvious ideal implementation - store the enum's raw value. To provide a single API to persist both  `UserDefaults`-supported types as well as enum values _backed_ by `UserDefaults`-supported types proved a little tricky; adding the requirement that everything needed to also work on `Optional` wrappers of any supported type, and the problem became more complex still. Once solved for my app, I thought why not package up?\n\n## Requirements\n\n- Xcode 12\n- Swift 5.3\n\n## Installation\n\n### Swift Package Manager\nAdd `https://github.com/AndrewBennet/PersistedPropertyWrapper.git` as a Swift Package Dependency in Xcode.\n\n### CocoaPods\nTo install via CocoaPods, add the following line to your Podfile:\n```\npod 'PersistedPropertyWrapper', '~\u003e 2.0'\n```\n\n### Manually\nCopy the contents of the `Sources` directory into your project.\n\n## Alternatives\n\n- [SwiftyUserDefaults](https://github.com/sunshinejr/SwiftyUserDefaults) has more functionality, but you are required to define your stored properties in a specific extension.\n- [AppStorage](https://developer.apple.com/documentation/swiftui/appstorage): native Apple property wrapper, but tailored to (and defined in) SwiftUI, and only available in iOS 14\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAndrewBennet%2FPersistedPropertyWrapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAndrewBennet%2FPersistedPropertyWrapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAndrewBennet%2FPersistedPropertyWrapper/lists"}