Git Product home page Git Product logo

foil's Introduction

Foil Actions Status

A lightweight property wrapper for UserDefaults done right


About

Read the post: A better approach to writing a UserDefaults Property Wrapper

Why the name?

Foil, as in "let me quickly and easily wrap and store this leftover food in some foil so I can eat it later." ๐ŸŒฏ ๐Ÿ˜‰

Foil:
noun
North America
A very thin, pliable, easily torn sheet of aluminum used for cooking, packaging, cosmetics, and insulation.

Usage

You can use @WrappedDefault for non-optional values and @WrappedDefaultOptional for optional ones. You may wish to store all your user defaults in one place, however, that is not necessary. Any property on any type can use this wrapper.

final class AppSettings {
    static let shared = AppSettings()

    @WrappedDefault(key: "flagEnabled")
    var flagEnabled = true

    @WrappedDefault(key: "totalCount")
    var totalCount = 0

    @WrappedDefaultOptional(key: "timestamp")
    var timestamp: Date?
}

// Usage

func userDidToggleSetting(_ sender: UISwitch) {
    AppSettings.shared.flagEnabled = sender.isOn
}

There is also an included example app project.

Using enum keys

If you prefer using an enum for the keys, writing an extension specific to your app is easy. However, this is not required. In fact, unless you have a specific reason to reference the keys, this is completely unnecessary.

enum AppSettingsKey: String, CaseIterable {
    case flagEnabled
    case totalCount
    case timestamp
}

extension WrappedDefault {
    init(wrappedValue: T, _ key: AppSettingsKey) {
        self.init(wrappedValue: wrappedValue, key: key.rawValue)
    }
}

extension WrappedDefaultOptional {
    init(_ key: AppSettingsKey) {
        self.init(key: key.rawValue)
    }
}

Observing changes

There are many ways to observe property changes. The most common are by using Key-Value Observing or a Combine Publisher. KVO observing requires the object with the property to inherit from NSObject and the property must be declared as @objc dynamic.

final class AppSettings: NSObject {
    static let shared = AppSettings()

    @WrappedDefaultOptional(key: "userId")
    @objc dynamic var userId: String?

    @WrappedDefaultOptional(key: "average")
    var average: Double?
}

Using KVO

let observer = AppSettings.shared.observe(\.userId, options: [.new]) { settings, change in
    print(change)
}

Using Combine

Note: that average does not need the @objc dynamic annotation, .receiveValue will fire immediately with the current value of average and on every change after.

AppSettings.shared.$average
    .sink {
        print($0)
    }
    .store(in: &cancellable)

Combine Alternative with KVO

Note: in this case, userId needs the @objc dynamic annotation and AppSettings needs to inherit from NSObject. Then receiveValue will fire only on changes to wrapped object's value. It will not publish the initial value as in the example above.

AppSettings.shared
    .publisher(for: \.userId, options: [.new])
    .sink {
        print($0)
    }
    .store(in: &cancellable)

Supported types

The following types are supported by default for use with @WrappedDefault.

Adding support for custom types is possible by conforming to UserDefaultsSerializable. However, this is highly discouraged. UserDefaults is not intended for storing complex data structures and object graphs. You should probably be using a proper database (or serializing to disk via Codable) instead.

  • Bool
  • Int
  • UInt
  • Float
  • Double
  • String
  • URL
  • Date
  • Data
  • Array
  • Set
  • Dictionary
  • RawRepresentable types

Additional Resources

Supported Platforms

  • iOS 13.0+
  • tvOS 13.0+
  • watchOS 6.0+
  • macOS 11+

Requirements

Installation

pod 'Foil', '~> 3.0.0'
dependencies: [
    .package(url: "https://github.com/jessesquires/Foil.git", from: "3.0.0")
]

Alternatively, you can add the package directly via Xcode.

Documentation

You can read the documentation here. Generated with jazzy. Hosted by GitHub Pages.

Contributing

Interested in making contributions to this project? Please review the guides below.

Also consider sponsoring this project or buying my apps! โœŒ๏ธ

Credits

Created and maintained by Jesse Squires.

License

Released under the MIT License. See LICENSE for details.

Copyright ยฉ 2021-present Jesse Squires.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.