Prephirences - Preϕrences

License Platform Language Issues Cocoapod Carthage compatible Build Status

Become a Patron! Buy me a coffee

Prephirences 是一个 Swift 库,它提供有用的协议和便捷方法来管理应用程序偏好设置、配置和应用状态。

  @Preference(key: "enabled")
  var enabled: Bool?

  @UserDefaultsPreference(key: "my.string.pref")
  var pref: String?

  @MutablePreference(preferences: UserDefaults.standard, key: "enabled")
  var enabled: Bool?
let userDefaults = UserDefaults.standard
if let enabled = userDefaults["enabled"] as? Bool {..}
userDefaults["mycolorkey", archive] = UIColor.blue

Preferences 不仅仅是 UserDefaults,还可以是:

即:任何实现简单协议 PreferencesType 的对象,该协议定义了键值存储方法。

您还可以组合多个偏好设置并以透明的方式使用它们(请参阅 组合

目录

用法

创建

PreferencesType 最简单的实现是 DictionaryPreferences

// From Dictionary
var fromDico = DictionaryPreferences(myDictionary)
// or literal
var fromDicoLiteral: DictionaryPreferences = ["myKey": "myValue", "bool": true]

// From filepath
if let fromFile = DictionaryPreferences(filePath: "/my/file/path") {..}
// ...in main bundle ##
if let fromFile = DictionaryPreferences(filename: "prefs", ofType: "plist") {..}

访问

您可以使用 PreferencesType 协议中定义的所有方法进行访问

if let myValue = fromDicoLiteral.object(forKey: "myKey") {..}
if let myValue = fromDicoLiteral["bool"] as? Bool {..}

var hasKey = fromDicoLiteral.hasObject(forKey: "myKey")
var myValue = fromDicoLiteral.bool(forKey: "myKey")
..

如果您想使用 RawRepresentable enum 进行访问。

enum MyKey: PreferenceKey/*String*/ {
   case Key1, Key2, ...
}
if let myValue = fromDicoLiteral.object(forKey: MyKey.Key1) {..}
var myValue = fromDicoLiteral.bool(forKey: MyKey.Key2)

⚠️ 必须导入 RawRepresentableKey,请参阅 设置

修改

可修改的偏好设置实现了协议 MutablePreferencesTypes

最简单的实现是 MutableDictionaryPreferences

var mutableFromDico: MutableDictionaryPreferences = ["myKey": "myValue"]

mutableFromDico["newKey"] = "newValue"
mutableFromDico.set("myValue", forKey: "newKey")
mutableFromDico.set(true, forKey: "newKey")
...

您可以使用运算符附加字典或其他 PreferencesType

mutableFromDico += ["newKey": "newValue", "otherKey": true]

您也可以删除一个偏好设置

mutableFromDico -= "myKey"

将运算符应用于一个偏好设置

您可以从任何 MutablePreferencesTypes 中提取一个 MutablePreference,并根据其值类型应用运算符

var intPref: MutablePreference<Int> = aPrefs.preference(forKey: "intKey")
var intPref: MutablePreference<Int> = aPrefs <| "intKey"

intPref++
intPref--
intPref += 30
intPref -= 30
intPref *= 20
intPref %= 7
intPref /= 3

switch(intPref) {
   case 1: println("one")
   case 2...10: println("not one or zero but...")
   default: println("unkwown")
}

var boolPref: MutablePreference<Bool> = aPrefs <| "boolKey")

boolPref &= false
boolPref |= true
boolPref != true

您还可以使用一些方法来更改值

var stringPref: MutablePreference<String> = userDefaults <| "stringKey"
stringPref.apply { value in
  return value?.uppercaseString
}

或者使用闭包转换值类型

let intFromBoolPref : MutablePreference<Int> = boolPref.transform { value in
  return (value ?? false) ? 1:0
}

转换和归档

在存储或访问值之前,可以应用符合协议 PreferenceTransformation 的转换。

这允许归档、更改类型、如果为 nil 则返回默认值等等。

您可以使用 subscript 获取和设置值

userDefaults["aKey", myTransformation] = myObject

if let object = userDefaults["aKey", myTransformation] {...}

如果您提取一个偏好设置,请使用 transformation 属性来设置转换

var aPref: MutablePreference<MyObject> = userDefaults <| "aKey"
aPref.transformation = myTransformation

或者,您可以使用一些实用函数来指定存储值满足条件时的默认值

public var intValueMin10: MutablePreference<Int> {
  get {
    return userDefaults.preference(forKey: "intKey")
          .whenNil(use: 100)
          .ensure(when: lessThan100, use: 100)
  }
  set {..}
}

归档

归档对于 NSUserDefaults 特别有用,因为 NSUserDefaults 无法存储所有类型的对象。以下函数可以通过将值转换为另一种类型来提供帮助

您可以使用这两种方法归档为 Data

userDefaults.set(objectToArchive: UIColor.blueColor(), forKey: "colorKey")
userDefaults["colorKey", .Archive] = UIColor.blueColor()

并使用以下方法解档

if let color = userDefaults.unarchiveObject(forKey: "colorKey") as? UIColor {..}
if let color = userDefaults["colorKey", .Archive]  as? UIColor {..}

如果您提取一个偏好设置,请使用 transformation 属性来设置归档模式

var colorPref: MutablePreference<UIColor> = userDefaults <| "colorKey"
colorPref.transformation = TransformationKey.Archive
colorPref.value = UIColor.redColor()
if let color = colorPref.value as? UIColor {..}

NSValueTransformer

您还可以对所有对象类型应用 NSValueTransformer,例如转换为 JSON

userDefaults["colorKey", myValueTransformerToJson] = myComplexObject

if let object = userDefaults["colorKey", myValueTransformerToJson] {...}

⚠️ allowsReverseTransformation 必须返回 true

存储 RawRepresentable 对象

对于像 enum 这样的 RawRepresentable 对象,您可以将计算属性 preferenceTransformation 用作 transformation

enum PrefEnum: String {
    case One, Two, Three
}
var pref: MutablePreference<PrefEnum> = preferences <| "enumKey"
pref.transformation = PrefEnum.preferenceTransformation
pref.value = PrefEnum.Two

一些实现

UserDefaults

UserDefaults 实现了 PreferencesType 并且可以使用相同的方法进行访问

let userDefaults = UserDefaults.standard

if let myValue = userDefaults["mykey"] as? Bool {..}

NSUserDefaults 也实现了 MutablePreferencesType 并且可以使用相同的方法进行修改

userDefaults["mykey"] = "myvalue"
// with type to archive
userDefaults["mykey", .Archive] = UIColor.blueColor()

Bundle

所有 Bundle 都实现了 PreferencesType,允许访问 Info.plist 文件。

例如,Bundle.main 包含许多关于您的应用程序的有用信息。

Prephirences 框架附带一些预定义的枚举,这些枚举在 苹果文档 中描述,并在 PropertyListKeys.swift 中定义。

let bundle = Bundle.main
let applicationName = bundle[.CFBundleName] as? String

NSUbiquitousKeyValueStore

要在 iCloud 中存储,NSUbiquitousKeyValueStore 也实现了 PreferencesType

请参阅组合章节,将 iCloud 偏好设置与其他偏好设置合并和同步。

键值编码 (Key Value Coding)

Foundation 类

您可以将响应隐式协议 NSKeyValueCoding 的对象包装在 KVCPreferencesMutableKVCPreferences

let kvcPref = MutableKVCPreferences(myObject)

请务必影响正确的对象类型

Swift 类

使用 ReflectingPreferences,您可以轻松访问 struct 或 swift 类。只需添加扩展。

struct PreferenceStruct {
    var color: String = "red"
    var age: Int
    let enabled: Bool = true
}
extension PreferenceStruct: ReflectingPreferences {}

然后您可以使用来自 PreferencesType 的所有函数

var pref = PreferenceStruct(color: "red", age: 33)
if pref["color"] as? String { .. }

Core Data

您可以将 NSManageObject 包装在 ManageObjectPreferencesMutableManageObjectPreferences

let managedPref = ManageObjectPreferences(myManagedObject)

Plist

有很多方法可以处理 plist 文件

钥匙串 (Keychain)

要存储到钥匙串中,请使用 KeychainPreferences 的一个实例

KeychainPreferences.sharedInstance // default instance with main bundle id
var keychain = KeychainPreferences(service: "com.github.example")

然后存储 StringData

keychain["anUserName"] = "password-encoded"

if let pass = keychain.stringForKey("anUserName") {..}

辅助功能

keychain.accessibility = .AccessibleAfterFirstUnlock

共享钥匙串项目

keychain.accessGroup = "AKEY.shared"

NSCoder

部分支持 NSCoderdictionary 不可用)

当您实现 NSCoding 时,您可以执行以下操作

init?(coder decoder: NSCoder) {
  self.init()
  self.intVar = decoder["intVarKey"] as? Int ?? 0
  // or self.intVar = decoder.integer(forKey: "intVar")
  self.stringVar = decoder["stringVarKey"] as? String ?? ""
}

func encodeWithCoder(coder: NSCoder) {
  coder["intVarKey"] = self.intVar
  coder["stringVarKey"] = self.stringVar
}

自定义实现

偏好设置

创建一个符合 PreferencesType 的自定义对象非常容易。

extension MyCustomPreferences: PreferencesType {
    func object(forKey: String) -> Any? {
        // return an object according to key
    }
    func dictionary() -> [String : Any] {
        // return a full dictionary of key value
    }
}

只有两个函数是强制性的,其他函数会自动映射,但可以为了性能或可读性而覆盖。

使用自定义键进行访问

您可以不使用 stringstring 常量,而是使用 enum 来定义键列表

首先使用 String 原始值创建您的 enum

enum MyEnum: String {
  case MyFirstKey
  case MySecondKey
}

然后为您的键添加下标

extension PreferencesType {
    subscript(key: MyEnum) -> Any? {
        return self[key.rawValue]
    }
}

最后访问您的信息

if let firstValue = bundle[.MyFirstKey] {..}

您可以对 MutablePreferencesType 执行相同的操作

使用前缀代理偏好设置

您可以像这样定义一个带有您自己的字符串前缀的偏好设置子类别

let myAppPrefs = MutableProxyPreferences(preferences: userDefaults, key: "myAppKey.")
// We have :
userDefaults["myAppKey.myKey"] == myAppPrefs["myKey"] // is true

这允许使用相同的键为所有偏好设置(用户默认设置)添加前缀

组合

组合允许将多个 PreferencesType 对象聚合为一个 PreferencesType

let myPreferences = CompositePreferences([fromDico, fromFile, userDefaults])
// With array literal
let myPreferences: CompositePreferences = [fromDico, fromFile, userDefaults]

// Mutable, only first mutable will be affected
let myPreferences: MutableCompositePreferences = [fromDico, fromFile, userDefaults]

您可以像任何 PreferencesType 一样访问或修改此复合偏好设置。

  1. 访问时,首先定义指定键值的偏好设置将响应
  2. 修改时,默认情况下会影响第一个可变偏好设置,但您可以将 MutableCompositePreferences 属性 affectOnlyFirstMutable 设置为 false 以影响所有可变偏好设置,从而允许您例如复制 iCloud 中的偏好设置

主要目标是为您的应用程序定义只读偏好设置(在代码或文件中)和一些可变偏好设置(例如 UserDefaultsNSUbiquitousKeyValueStore)。然后您可以访问一个偏好设置值,而无需关心来源。

管理偏好设置实例

如果您想在框架中使用 Prephirences,或者想在不添加类之间依赖关系的情况下获取 Preferences,您可以将任何 PreferencesType 注册到 Prephirences

作为共享实例

Prephirences.sharedInstance = myPreferences

或者通过提供一个 Hashable

Prephirences.register(preferences: myPreferences, forKey: "myKey")
Prephirences.instances()["myKey"] = myPreferences
Prephirences.instances()[NSStringFromClass(self.dynamicType)] = currentClassPreferences

然后您可以在任何地方访问它

if let pref = Prephirences.instance(forKey: "myKey") {..}
if let pref = Prephirences.instances()["myKey"] {..}

远程偏好设置

通过使用远程偏好设置,您可以远程控制应用程序的行为。

如果您使用 AlamofireAlamofire-Prephirences 将帮助您从远程 JSON 或 Plist 加载偏好设置

加密您的偏好设置

您可以使用框架 CryptoPrephirences 使用来自 CryptoSwift 的密码加密/解密您的偏好设置

设置

使用 Cocoapods

CocoaPods 是 Objective-C 和 Swift 的集中式依赖项管理器。 请转到 这里 了解更多信息。

  1. 将项目添加到您的 Podfile

    use_frameworks!
    
    pod 'Prephirences'
  2. 运行 pod install 并打开 .xcworkspace 文件以启动 Xcode。

对于 core data

添加 pod 'Prephirences/CoreData'

对于 RawRepresentable 键

添加 pod 'Prephirences/RawRepresentableKey'

对于 PropertyListKeys

添加 pod 'Prephirences/Keys'

使用 Carthage

Carthage 是 Objective-C 和 Swift 的去中心化依赖项管理器。

  1. 将项目添加到您的 Cartfile

    github "phimage/Prephirences"
    
  2. 运行 carthage update 并按照 附加步骤 将 Prephirences 添加到您的项目。

使用 xcode 项目

  1. 将 Prephirences.xcodeproj 拖到您的项目/工作区,或打开它以编译它
  2. 将 Prephirences 框架添加到您的项目

标志

kodlian 提供