箔片 5.1.2

Foil 5.1.2

Jesse Squires 维护。



Foil 5.1.2

Foil Actions Status

为 UserDefaults 实现的一个轻量级、正确的属性包装器


关于

阅读文章:关于编写UserDefaults Property Wrapper的更好方法

为什么叫 Foil?

Foil,正如“让我快速地将这个剩余的食物用 foil 插好并存储起来,以便我以后可以吃”的含义。🌯 😉

Foil:
名词
北美
一种非常薄、可塑性、易撕的铝箔,用于烹饪、包装、化妆品和绝缘。

用法

您可以使用 @FoilDefaultStorage 用于非可选值,以及 @FoilDefaultStorageOptional 用于可选值。不过,您不一定需要将所有用户默认存储在一个地方。任何类型上的任何属性都可以使用这个包装器。

final class AppSettings {
    static let shared = AppSettings()

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

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

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

// Usage

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

还包含一个示例应用项目。

使用 enum

如果您更喜欢使用 enum 作为键,编写特定于您应用的扩展很容易。但这不是必须的。事实上,除非您有特定理由需要引用键,否则这完全是多余的。

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

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

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

观察变化

许多方法可以观察属性的变化。最常见的方法是使用 Key-Value Observing (KVO) 或 Combine Publisher。使用 KVO 观察,需要对象继承自 NSObject,并且属性必须声明为 @objc dynamic

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

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

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

使用 KVO

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

使用 Combine

注意

average 不需要 @objc dynamic 注解,.receiveValue 会立即发射当前 average 的值,并且在每次更改之后都会发射。

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

使用 KVO 的 Combine 替代方案

注意

在这种情况下,userId 需要编写 @objc dynamic 注解,而 AppSettings 需要继承自 NSObject。然后,receiveValue 将仅在外部对象值更改时触发,它不会像上面示例那样发布初始值。

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

支持的类型

以下类型默认支持与 @FoilDefaultStorage 一起使用。

重要

通过遵循 UserDefaultsSerializable可以从支持自定义类型,但是高度不建议这样做,因为默认情况下所有 plist 类型都得到支持。UserDefaults 不是一个存储复杂数据结构和对象图的设计。您可能应该使用一个合适的数据库(或其他通过 Codable 序列化到磁盘)。

虽然 Foil 默认支持存储 Codable 类型,但应谨慎使用,并且 仅限于 具有少量属性的轻量级对象。

  • Bool
  • Int
  • UInt
  • Float
  • Double
  • String
  • URL
  • Date
  • Data
  • Array
  • Set
  • Dictionary
  • RawRepresentable 类型
  • Codable 类型

警告

如果您正在存储自定义的 Codable类型,并使用由Foil提供的默认的UserDefaultsSerializable实现,那么您必须使用属性包装器的可选变体@FoilDefaultStorageOptional。这样可以将您的 Codable类型进行破坏性的变更(例如:添加或删除属性)。或者,您可以提供一个支持迁移的自定义 Codable实现,或提供一个处理编码/解码错误的自定义UserDefaultsSerializable实现。请参考下面的示例。

Codable示例

// Note: uses the default implementation of UserDefaultsSerializable
struct User: Codable, UserDefaultsSerializable {
    let id: UUID
    let name: String
}

// Yes, do this
@FoilDefaultStorageOptional(key: "user")
var user: User?

// NO, do NOT this
// This will crash if you change User by adding/removing properties
@FoilDefaultStorage(key: "user")
var user = User()

其他资源

支持的平台

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

需求

安装

CocoaPods

pod 'Foil', '~> 5.0.0'

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/jessesquires/Foil.git", from: "5.0.0")
]

或者,您可以直接通过Xcode添加包

文档

您可以在此处阅读文档。由jazzy生成。由GitHub Pages托管。

参与贡献

如果您想为此项目做出贡献,请查看以下指南。

此外,考虑赞助此项目购买我的应用!✌️

致谢

Jesse Squires 创建和维护。

许可协议

基于MIT许可证发布。详情请参阅LICENSE文件。

版权所有 © 2021-至今 Jesse Squires。