PropertyKit 1.1

PropertyKit 1.1

Taeho Lee 维护。



  • Taeho Lee

PropertyKit

swift cocoapods compatible carthage compatible language platform swift

轻量级、严格的基于协议的 PropertyKit,可以帮助您轻松且安全地在各种情况下处理 iOS、macOS 和 tvOS 上大型 Swift 项目的保证值、键或类型。

安装

详细指南

CocoaPods

pod 'PropertyKit'

Carthage

github "metasmile/PropertyKit"

Swift 包管理器

.Package(url: "https://github.com/metasmile/PropertyKit.git")

模块

PropertyDefaults

管理 UserDefaults 的最简单且可靠的方式。PropertyDefaults 会自动将 Swift 属性的值和数据类型绑定到 UserDefaults 的键和值。它强制采用仅关注语法驱动的值处理的协议扩展模式,因此有助于避免不安全的使用字符串键。因此,Swift 编译器将自然地保护所有缺失或重复的状态。

PropertyDefaults 是由 nmdias 提出的一个全新的 DefaultsKit 分支,采用完全不同的方法。

特性

  • Swift 4 编解码支持
  • 编译时对 UserDefaults 的保证
  • 键、类型和值的关联安全性,不使用字符串字面量
  • 结构扩展、协议驱动,而非意向式
  • 权限控制
  • 自动私有作用域 - 文件、类、结构体或函数内部

使用方法

用一个示例来定义带有基本 Codable 类型自动 UserDefaults 键

extension Defaults: PropertyDefaults {
    public var autoStringProperty: String? {
        set{ set(newValue) } get{ return get() }
    }
    public var autoDateProperty: Date? {
        set{ set(newValue) } get{ return get() }
    }
}
var sharedDefaults = Defaults()
sharedDefaults.autoStringProperty = "the new value will persist in shared scope"
// sharedDefaults.autoStringProperty == Defaults.shared.autoStringProperty

Defaults.shared.autoStringProperty = "another new value will persist in shared scope"
// Defaults.shared.autoStringProperty == sharedDefaults.autoStringProperty

var localDefaults = Defaults(suiteName:"local")
localDefaults.autoStringProperty = "the new value will persist in local scope"
// localDefaults.autoStringProperty != Defaults.shared.autoStringProperty

直接以 Codable 类型保存/加载

public struct CustomValueType: Codable{
    var key:String = "value"
    var date:Date?
    var data:Data?
}
extension Defaults: PropertyDefaults {
    // non-optional - must define the default value with the keyword 'or'
    public var autoCustomNonOptionalProperty: CustomValueType {
        set{ set(newValue) } get{ return get(or: CustomValueType()) }
    }
    // optional with/without setter default value
    public var autoCustomOptionalProperty: CustomValueType? {
        set{ set(newValue) } get{ return get() }
    }
    public var autoCustomOptionalPropertySetterDefaultValue: CustomValueType? {
        set{ set(newValue, or: CustomValueType()) } get{ return get() }
    }
}

通过 Swift 编译器强保证唯一密钥。

//CodeFile1_ofLargeProject.swift
protocol MyDefaultsKeysUsingInA : PropertyDefaults{
    var noThisIsMyKeyNotYours:Int?{ get }
}
extension Defaults : MyDefaultsKeysUsingInA{
    var noThisIsMyKeyNotYours:Int?{ set{ set(newValue) } get{ return get() } }
}

//CodeFile2_ofLargeProject.swift
protocol MyDefaultsKeysUsingInB : PropertyDefaults{
    var noThisIsMyKeyNotYours:Int?{ get }
}
extension Defaults : MyDefaultsKeysUsingInB{
    var noThisIsMyKeyNotYours:Int?{ set{ set(newValue) } get{ return get() } }
}
❗️Swift Compiler Error
~.swift:30:9: Invalid redeclaration of 'noThisIsMyKeyNotYours'
~.swift:21:9: 'noThisIsMyKeyNotYours' previously declared here

按照这种模式,正如您所知,您还可以通过协议来控制访问权限。这意味着您可以使用 'private' 或 'file-private' 默认访问修饰符。

// MyFile.swift
fileprivate protocol PrivateDefaultKeysInThisSwiftFile: PropertyDefaults{
    var filePrivateValue: String? {set get}
}

extension Defaults: PrivateDefaultKeysInThisSwiftFile {
    public var filePrivateValue: String? {
        set{ set(newValue) } get{ return get() }
    }
}

// Can access - 👌
Defaults.shared.filePrivateValue
// MyOtherFile.swift

// Not able to access - ❌
Defaults.shared.filePrivateValue

是的,这是一种打破我们的设计意图的方法。

var p1:Int{
    Defaults.shared.set(2)  
    return Defaults.shared.get(or:0)  
}
var p2: Int{
    return Defaults.shared.get(or:0)  
}

p1 // == 2
p2 // == 0
//It means that are function/property-scoped capsulated defaults values.

PropertyWatchable

基于 NSKeyValueObservation 的协议扩展。它简单地允许一个类对象成为类型安全的 keypath 观察对象。所有观察者都将自动分配一个唯一的观察者标识符,从而防止重复的回调调用,并可以让你原子性地管理连接队列之间的关键值流。

特性

  • 仅使用协议即可创建观察对象。
  • Swift 属性字面量基于的 keypath 观察方式。
  • 严格保证回调参数的类型。
  • 支持自动唯一标识符。
  • 支持文件范围观察者移除。
  • 支持队列私有的原子操作。

使用方法

使用它的最简单的例子。

class WatchableObject:NSObject, PropertyWatchable{
    @objc dynamic
    var testingProperty:String?
}

let object = WatchableObject()
object.watch(\.testingProperty) {
    object.testingProperty == "some value"
    //Do Something.
}

object.testingProperty = "some value"

所有选项和强类型参数都与 NSKeyValueObservation 相同。

// Default option is the default of NSKeyValueObservation (.new)
// (WatchableObject, NSKeyValueObservedChange<Value>)
object.watch(\.testingProperty, options: [.initial, .new, .old]) { (target, changes) in     
    target.testingProperty == "some value"
    //Dd Something.
}
let object = WatchableObject()
object.testingProperty = "initial value"
config.watch(\.testingProperty, options: [.initial]) { (o, _) in
    o.testingProperty == "initial value"
}

支持自动按行生成标识符。

object.watch(\.testingProperty) {
    // Listening as a unique observer 1
}

object.watch(\.testingProperty) {
    // Listening as a unique observer 2
}

object.watch(\.testingProperty, id:"myid", options:[.old]) {
    // Listening as an observer which has identifier "myid"
}

// total 3 separated each observers are listening each callbacks.

支持使用不同选项来移除观察。

// Remove only an observer which has "myid" only
object.unwatch(\.testingProperty, forIds:["myid"])

// Remove all observers that are watching ".testingProperty"
object.unwatch(\.testingProperty)

//Automatically remove all observers in current file.
object.unwatchAllFilePrivate()

//Automatically remove entire observers in application-wide.
object.unwatchAll()