A protocol-centric, type and queue safe key-value workflow.

Related tags

Database PropertyKit
Overview

PropertyKit

swift cocoapods compatible carthage compatible language platform swift

Light-weight, strict protocol-first styled PropertyKit helps you to easily and safely handle guaranteed values, keys or types on various situations of the large-scale Swift project on iOS, macOS and tvOS.

Installation

Detail Guide

CocoaPods

pod 'PropertyKit'

Carthage

github "metasmile/PropertyKit"

Swift Package Manager

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

Modules

PropertyDefaults

The simplest, but reliable way to manage UserDefaults. PropertyDefaults automatically binds value and type from Swift property to UserDefaults keys and values. It forces only protocol extension pattern that is focusing on syntax-driven value handling, so it helps to avoid unsafe String key use. Therefore, natually, Swift compiler will protect all of missing or duplicating states with its own.

PropertyDefaults is new hard fork of DefaultsKit by nmdias with entirely different approaches.

Features

  • Swift 4 Codable Support
  • Compile-time UserDefaults guaranteeing.
  • Key-Type-Value relationship safety, no String literal use.
  • Structural extension-protocol-driven, instead of an intension.
  • Permission control
  • Automatic private scope - In File, Class or Struct, Function

Usage

An example to define automatic UserDefaults keys with basic Codable types:

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

Directly save/load as Codable type

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() }
    }
}

Strongly guaranteeing unique key with Swift compiler.

//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

With this pattern, as you know, you also can control access permission with the protocol. It means you can use 'private' or 'file-private' defaults access.

// 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

And, Yes, It's a hack way to crack our design intention.

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

A protocol extension based on NSKeyValueObservation. It simply enables to let a class object become a type-safe keypath observable object. And unique observer identifier will be assigned to all observers automatically. That prevents especially duplicated callback calls and so it can let you atomically manage a bunch of key-value flows between its joined queues.

Features

  • Making an observable object with only protocol use.
  • Swift property literal based keypath observation.
  • Strictful type-guaranteed callback parameter support.
  • Automatic unique identifier support.
  • File-scoped observer removing support.
  • Queue-private atomic operation support.

Usage

The simplest example to use.

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"

All options and strongly typed-parameters are same with 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"
}

Automatic line by line identifier support.

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 observations with various options.

// 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()
You might also like...
📕A single value proxy for NSUserDefaults, with clean API.

OneStore A single value proxy for NSUserDefaults, with clean API. With OneStore… Create one proxy(an OneStore object) for each NSUserDefaults value. M

Safe and easy wrappers for common Firebase Realtime Database functions.

FirebaseHelper FirebaseHelper is a small wrapper over Firebase's realtime database, providing streamlined methods for get, set, delete, and increment

Safe and easy wrappers for RealmSwift

RealmWrapper RealmWrapper is wrapper library for RealmSwift in realm-cocoa If you use RealmWrapper, you can easily use UI update through Notification

TypedDefaults is a utility library to type-safely use NSUserDefaults.

TypedDefaults TypedDefaults is a utility library to type-safely use NSUserDefaults. Motivation The talk Keep Calm and Type Erase On by Gwendolyn Westo

A Generic CoreData Manager to accept any type of objects. Fastest way for adding a Database to your project.
A Generic CoreData Manager to accept any type of objects. Fastest way for adding a Database to your project.

QuickDB FileManager + CoreData ❗️ Save and Retrieve any thing in JUST ONE line of code ❗️ Fast usage dataBase to avoid struggling with dataBase comple

A percentage type for Swift

Percentage A percentage type for Swift Makes percentages more readable and type-safe, for example, for APIs that currently accept a fraction Double. -

Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, configurations and app-state. UserDefaults
Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, configurations and app-state. UserDefaults

Prephirences - Preϕrences Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, co

Classes-and-structures-in-swift - This source files show what is the difference between class and structure

This source files show what is the difference between class and structure You ca

Elegant library to manage the interactions between view and model in Swift
Elegant library to manage the interactions between view and model in Swift

An assistant to manage the interactions between view and model ModelAssistant is a mediator between the view and model. This framework is tailored to

Comments
  • PropertyWatchable: Queue-safe atomic callback support.

    PropertyWatchable: Queue-safe atomic callback support.

    For instance, about this situation.

    
    extension DispatchQueue {
        public class var currentLabel: String {
            return String(validatingUTF8: __dispatch_queue_get_label(nil)) ?? "anonymous"
        }
    }
    
    
    let object = SomeWatchableObject()
    
    //main queue
    object.watch(\.someWatchableProperty){
          DispatchQueue.currentLabel == DispatchQueue.main.label
          // automatic synchronized value in same queue (=main queue)
    }
    
    DispatchQueue(label:"some other watching queue").async{
           object.watch(\.someWatchableProperty){
                  DispatchQueue.currentLabel == "some other watching queue"
                  // automatic synchronized value in same queue
           }
    }
    
    DispatchQueue(label:"some private queue").async{
            object.someWatchableProperty = "New value 1"
            object.someWatchableProperty = "New value 2"
            /// ... ~
    }
    
    feature 
    opened by metasmile 0
Releases(1.0)
Owner
gitmerge
gitmerge
An elegant, fast, thread-safe, multipurpose key-value storage, compatible with all Apple platforms.

KeyValueStorage An elegant, fast, thread-safe, multipurpose key-value storage, compatible with all Apple platforms. Supported Platforms iOS macOS watc

null 3 Aug 21, 2022
A type-safe, protocol-based, pure Swift database offering effortless persistence of any object

There are many libraries out there that aims to help developers easily create and use SQLite databases. Unfortunately developers still have to get bogged down in simple tasks such as writing table definitions and SQL queries. SwiftyDB automatically handles everything you don't want to spend your time doing.

Øyvind Grimnes 489 Sep 9, 2022
An Objective-C wrapper for RocksDB - A Persistent Key-Value Store for Flash and RAM Storage.

ObjectiveRocks ObjectiveRocks is an Objective-C wrapper of Facebook's RocksDB - A Persistent Key-Value Store for Flash and RAM Storage. Current RocksD

Iskandar Abudiab 56 Nov 5, 2022
An efficient, small mobile key-value storage framework developed by WeChat. Works on Android, iOS, macOS, Windows, and POSIX.

中文版本请参看这里 MMKV is an efficient, small, easy-to-use mobile key-value storage framework used in the WeChat application. It's currently available on Andr

Tencent 15.4k Jan 6, 2023
YapDB is a collection/key/value store with a plugin architecture. It's built atop sqlite, for Swift & objective-c developers.

YapDatabase is a collection/key/value store and so much more. It's built atop sqlite, for Swift & Objective-C developers, targeting macOS, iOS, tvOS &

Yap Studios 3.3k Dec 29, 2022
Key-Value store for Swift backed by LevelDB

SwiftStore Key/Value store for Swift backed by LevelDB. Usage Create instances of store import SwiftStore // Create a store. let store = SwiftStore(s

Hemanta Sapkota 119 Dec 21, 2022
Typed key-value storage solution to store Codable types in various persistence layers with few lines of code!

?? Stores A typed key-value storage solution to store Codable types in various persistence layers like User Defaults, File System, Core Data, Keychain

Omar Albeik 94 Dec 31, 2022
SQLite.swift - A type-safe, Swift-language layer over SQLite3.

SQLite.swift provides compile-time confidence in SQL statement syntax and intent.

Stephen Celis 8.7k Jan 3, 2023
Swift APIs for SQLite: Type-safe down to the schema. Very, very, fast. Dependency free.

Lighter Lighter is a set of technologies applying code generation to access SQLite3 databases from Swift, e.g. in iOS applications or on the server. L

Lighter.swift 330 Dec 26, 2022
A CLI tool for the survey of the SSH-Key strength in your GitHub organization members.

GitHub organization SSH-keys checker A CLI tool for the survey of the SSH-Key strength in your GitHub organization members. Requirements macOS 12.0+ S

hugehoge 1 Dec 11, 2021