Zephyr synchronizes specific keys and/or all of your UserDefaults over iCloud using NSUbiquitousKeyValueStore.

Overview

Zephyr 🌬️

Effortlessly sync UserDefaults over iCloud

Swift Support Platform CocoaPods SwiftPM Compatible


About

Zephyr synchronizes specific keys and/or all of your UserDefaults over iCloud using NSUbiquitousKeyValueStore.

Zephyr has built in monitoring, allowing it to sync specific keys in the background as they change.

For the latest updates, refer to the Releases tab.

Features

  • CocoaPods and SwiftPM Support
  • Syncs specific UserDefaults keys or all of your UserDefaults.
  • Background monitoring and synchronization between UserDefaults and NSUbiquitousKeyValueStore
  • Detailed Logging

Installation Instructions

Swift Version Branch Name Will Continue to Receive Updates?
5.1+ master Yes
5.0 swift5.0 No
4.2 swift4.2 No
4.1 swift4.1 No
3.2 swift3.2 No
3.1 swift3.1 No

CocoaPods

pod 'Zephyr' # Swift 5.1+
pod 'Zephyr', :git => 'https://github.com/ArtSabintsev/Zephyr.git', :branch => 'swift5.0' # Swift 5.0
pod 'Zephyr', :git => 'https://github.com/ArtSabintsev/Zephyr.git', :branch => 'swift4.2' # Swift 4.2
pod 'Zephyr', :git => 'https://github.com/ArtSabintsev/Zephyr.git', :branch => 'swift4.1' # Swift 4.1
pod 'Zephyr', :git => 'https://github.com/ArtSabintsev/Zephyr.git', :branch => 'swift3.2' # Swift 3.2
pod 'Zephyr', :git => 'https://github.com/ArtSabintsev/Zephyr.git', :branch => 'swift3.1' # Swift 3.1

Swift Package Manager

.Package(url: "https://github.com/ArtSabintsev/Zephyr.git", majorVersion: 3)

Manual

  1. Download Zephyr
  2. Copy Zephyr.swift into your project.

Setup

Turn on iCloud Sync in Xcode

In Xcode, open your app's project/workspace file:

  • Click on your Project
  • Click on one of your Targets
  • Click on Capabilities
  • Turn on iCloud syncing
  • Under Services, make sure to check Key-value storage
  • Repeat for all Targets (if necessary)

How to turn on iCloud Key Value Store Syncing

Integrate Zephyr into your App

Before performing each sync, Zephyr automatically checks to see if the data in UserDefaults or NSUbiquitousKeyValueStore is newer. To make sure there's no overwriting going on in a fresh installation of your app on a new device that's connected to the same iCloud account, make sure that your UserDefaults are registered BEFORE calling any of the Zephyr methods. One way to easily achieve this is by using the UserDefaults Register API.

Sync all UserDefaults

Zephyr.sync()

Sync a specific key or keys (Variadic Option)

Zephyr.sync(keys: "MyFirstKey", "MySecondKey", ...)

Sync a specific key or keys (Array Option)

Zephyr.sync(keys: ["MyFirstKey", "MySecondKey"])

Add/Remove Keys for Background Monitoring (Variadic Option)

Zephyr.addKeysToBeMonitored(keys: "MyFirstKey", "MySecondKey", ...)
Zephyr.removeKeysFromBeingMonitored(keys: "MyFirstKey", "MySecondKey", ...)

Add/Remove Keys for Background Monitoring (Array Option)

Zephyr.addKeysToBeMonitored(keys: ["MyFirstKey", "MySecondKey"])
Zephyr.removeKeysFromBeingMonitored(keys: ["MyFirstKey", "MySecondKey"])

Toggle Automatic Calling of NSUbiquitousKeyValueStore's Synchronization method

Zephyr.syncUbiquitousKeyValueStoreOnChange = true // Default
Zephyr.syncUbiquitousKeyValueStoreOnChange = false // Turns off instantaneous synchronization

Debug Logging

Zephyr.debugEnabled = true // Must be called before sync(_:)
Zephyr.sync()

Sample App

Please ignore the Sample App as I did not add any demo code in the Sample App. It's only in this repo to add support for Carthage.

Created and maintained by

Arthur Ariel Sabintsev

Comments
  • Background sync not triggered

    Background sync not triggered

    I'm currently trying to get this set up to allow me to sync an array between devices.

    In my AppDelegate I add

    Zephyr.debugEnabled = true
    Zephyr.addKeysToBeMonitored(keys: "defaultToSync")
    Zephyr.sync(keys: "defaultToSync")
    

    Which when launching the second device will pull in what value has been set.

    I then change the value using:

    UserDefaults().set(value, forKey: "defaultToSync")
    Zephyr.sync(keys: "defaultToSync")
    

    My second device never seems to pick up that things have changed, the device making the change does say it has synced TO iCloud.

    My understanding is that the key being monitored should at some point see the change?

    Any help is appreciated.

    opened by evanrobertson 11
  • Allow custom UserDefaults object, bug fixed

    Allow custom UserDefaults object, bug fixed

    Added an optional parameter to Zephyr.sync(), taking a custom UserDefaults object and using that in place of always using the container-wide UserDefaults.standard.

    Fixed bug resulting in UserDefaults.standard being used despite passing in a custom UserDefaults object to the variable-arguments sync() function (when no keys were passed in)

    opened by albertwujj 10
  • using Zephyr with a suiteName

    using Zephyr with a suiteName

    I am just getting started with Zephyr, I want to use it sync my UserDefaults between iPad and iOS version of my app. I have set it up, and it doesn't seem to find the values across devices. Both devices are logged into the same iCloud account, and in debug mode I see that Zephyr is syncing - but each devices seems to find a unique instance. (this is in the simulator on both devices). Is this addressed via a UserDefaults SuiteName?

    Question 
    opened by TheApApp 9
  • Swift 3 Support

    Swift 3 Support

    This PR will remain open until Xcode 8.0 GM is released.

    Initial conversion to Swift 3 was done in Xcode 8.0b2.

    All work for Swift 3 compatibility will be done in this branch.

    opened by ArtSabintsev 9
  • Attempted fix for initial load issue.

    Attempted fix for initial load issue.

    All parts of the guard statement have been split into let statements and two separate if statements.

    If localStoredData == nil we still want to synchronize.

    See issue #48.

    Potential Bug Enhancement 
    opened by aedificator-nl 8
  • follow up override issue

    follow up override issue

    Sorry for my late response. answering your question here: https://github.com/ArtSabintsev/Zephyr/issues/45#event-2843850328

    first in: func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?)

    I register defaults, where:

    let emptyData = Data()
    UserDefaults.standard.register(defaults: [subscription.identifier: emptyData])
    Zephyr.addKeysToBeMonitored(keys: [subscription.identifier])
    

    later after checking the status of the user subscription I store the subscription in UserDefaults to later sync:

    let encoder = PropertyListEncoder()
    let statusData = try! encoder.encode(status)                
    UserDefaults.standard.set(statusData, forKey: subscription.identifier)
    Zephyr.sync(keys: [subscription.identifier])
    

    And here is where the override issue happens. I managed to fix it in my phone by removing the key from iCloud with NSUbiquitousKeyValueStore.default.removeObject(forKey:) But trying with a different phone happen again.

    If you could give me some hint here I would really appreciated

    Question 
    opened by luicm 8
  • zephyrRemoteStoreDictionary[ZephyrSyncKey] reports incorrect time

    zephyrRemoteStoreDictionary[ZephyrSyncKey] reports incorrect time

    Initially, when I reported this issue, I thought it was due to a synchronization timing / data race issue, but I have since found otherwise.

    It appears that the date stored in zephyrRemoteStoreDictionary[ZephyrSyncKey] often supplies the incorrect time, thus causing data lost for the local store. Although I have yet to pinpoint the cause of the issue, this key fairly consistently (2 out of every 3 calls) reports a time that is ahead of the local time. Unfortunately, this means that when updating a default in the local store that is newer than the default stored remotely, the older remote value trumps the new local value.

    I will continue looking into the issue and see if I can find out any additional information. Hopefully we can get this fixed!

    Thank you for this project - saved me a good chunk of time, and it's beautifully written! 🍻

    opened by Sam-Spencer 8
  • Use of unresolved identifier 'DispatchQueueAttributes'

    Use of unresolved identifier 'DispatchQueueAttributes'

    Hey Arthur!

    Just loaded this up in Xcode 8 beta 4 and I'm getting this error on line 75.

    Use of unresolved identifier 'DispatchQueueAttributes'

    private let zephyrQueue = DispatchQueue(label: "com.zephyr.queue", attributes: DispatchQueueAttributes.serial);

    It looks like this initializer is only available in iOS 10+.

    opened by jstheoriginal 8
  • [OSX] UIApplicationWillEnterForegroundNotification is iOS only

    [OSX] UIApplicationWillEnterForegroundNotification is iOS only

    screenshot 2015-11-24 20 25 00

    Is it iOS thing only, viz. doc: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/#//apple_ref/c/data/UIApplicationWillEnterForegroundNotification

    opened by vlafiser 8
  • Issue when changing multiple keys in macOS Monterey

    Issue when changing multiple keys in macOS Monterey

    First off: Thank you for this library. This is exactly what I was looking for.

    There seems to be a sync issue with macOS Monterey (tested version: 12.0.1 (21A558))

    It seems that Apple changed the behavior on how it posts the NSUbiquitousKeyValueStore.didChangeExternallyNotification notification.

    Formerly, notification.userInfo?[NSUbiquitousKeyValueStoreChangedKeysKey] contained ALL changed keys (including ZephyrSyncKey). In my tests, this is no longer the case. Instead, the notification gets posted multiple times, with different values. Here is what happens in my scenario:

    We have Client A and Client B. Lets say A changes 2 keys. What happens is:

    Zephyr:

    • Receives NSUbiquitousKeyValueStore.didChangeExternallyNotification notification for key 1, stores remote value to local user defaults.
    • Zeyphr sets local sync date
    • Receives NSUbiquitousKeyValueStore.didChangeExternallyNotification notification for key 2, throws it away, because local sync date is newer
    • Receives NSUbiquitousKeyValueStore.didChangeExternallyNotification notification for key ZephyrSyncKey

    https://github.com/ArtSabintsev/Zephyr/blob/d86fe8ccc70b599ffd9adde55ada042910d045a1/Sources/Zephyr.swift#L456-L459

    In this scenario, the second value was thrown out and both apps are no longer in sync.

    I can't tell if this is a (beta) bug or if this is the new, expected behavior. I can't think of a good way to fix this, as we would now need to store the sync date of each property - or somehow batch all those updates coming in.

    Potential Bug 
    opened by paxos 7
  • Make this universally compile with current versions of Swift and Xcode

    Make this universally compile with current versions of Swift and Xcode

    This fixes a couple of issues that prevent the package from compiling with current versions of Swift and Xcode:

    • commit 6357a65:
      • updates Package.swift format to 4.0 as required by Swift 5 (and recommended for Swift 4)
    • commit 9ba6be1:
      • tracks the .UIApplicationWillEnterForeground notification name change (Swift 4.2 onwards)
    • commit eae57a6:
      • protects UIKit specifics with #if os() so Zephyr now compiles for macOS as well
    opened by rhx 7
Releases(3.7.1)
  • 3.7.1(Oct 10, 2022)

  • 3.6.3(Mar 2, 2022)

  • 3.6.2(Nov 7, 2021)

    • #55: Fixed a race condition that was accidentally overlooked when zephyrQueue was introduced. Huge thanks to @Tunous for pointing out the issue and submitting the fix.
    Source code(tar.gz)
    Source code(zip)
  • 3.6.1(Nov 22, 2020)

    This is a version bump that only affects folks using SPM. This change results in less metadata files being brought into an installation now that the architecture of this repo has changed.

    Source code(tar.gz)
    Source code(zip)
  • 3.6.0(Jun 15, 2020)

    Synchronization is Hard

    Thanks to the diligence of @aedificator-nl in (#47 & #48), a long standing bug was fixed that would early-exit an initial synchronization on the first attempted synchronization on a secondary device sharing the same iCloud account. In other words, syncing wouldn't occur right away until after the second device was had a subsequent synchronization attempt performed. I think this bug has been in the library for a long time, if not since the beginning, so I applaud @aedificator-nl for taking the time and diligence to find the nefarious line of code and working through the solution.

    Source code(tar.gz)
    Source code(zip)
  • 3.5.1(Jun 13, 2020)

  • 3.5.0(Sep 15, 2019)

  • 3.4.2(Aug 30, 2019)

    On working on a personal application of mine, I noticed that synchronization on a second/subsequent device did not work on that device's first launch of an application. After further investigation, I noticed that the syncFromCloud method did not actually post a notification on completion. This has now been fixed.

    Source code(tar.gz)
    Source code(zip)
  • 3.4.1(Aug 8, 2019)

    I fixed the Package.swift so that it is now compatible with Xcode 11 and the latest Swift Package Manifest file (// swift-tools-version:4.0).

    Source code(tar.gz)
    Source code(zip)
  • 3.4.0(Apr 19, 2019)

  • 3.3.0(Mar 31, 2019)

    As of Zephyr v3.3.0, all future changes on master will be done in Xcode 10.2 using Swift 5.0.

    For those using Swift v4.2, please check out the swift4.2 branch or version 3.2.0 - both point to the same commit hash.

    Source code(tar.gz)
    Source code(zip)
  • 3.2.0(Sep 17, 2018)

    As of Zephyr v3.2.0, all future changes on master will be done in Xcode 10 using Swift 4.2.

    For those using Swift v4.1.0, please check out the swift4.1 branch or version 3.1.2 - both point to the same commit hash.

    Source code(tar.gz)
    Source code(zip)
  • 3.1.2(Apr 23, 2018)

  • 3.1.1(Apr 23, 2018)

  • 3.1.0(Mar 29, 2018)

  • 3.0.2(Mar 15, 2018)

    • Updated Podspec file.
    • Removed .swift-version file, as it's been deprecated.
    • Removed watchOS support since there are a few insurmountable issue (and because it seems no one was using or requesting this support).
    Source code(tar.gz)
    Source code(zip)
  • 3.0.1(Oct 19, 2017)

    • Fixes #25. When converting to the codebase to Swift 4, the @objcMembers keyword was missing, so the KVO method was never being hit. This has been addressed.
    Source code(tar.gz)
    Source code(zip)
  • 3.0.0(Sep 13, 2017)

    Zephyr v3.0.0 adds support for Swift 4 / iOS 11 / Xcode 9. Only minor changes were made under-the-hood.

    Moving forward, only support for the Swift 4 codebase (on master) will be maintained.

    | Swift Version | Branch Name | Will Continue to Receive Updates? | ------------- | ------------- | ------------- | 4.0 | master | Yes | 3.2 | swift3.2 | No | 3.1 | swift3.1 | No

    Source code(tar.gz)
    Source code(zip)
  • 2.2.3(Mar 5, 2017)

  • 2.2.2(Mar 5, 2017)

  • 2.2.1(Mar 5, 2017)

  • 2.2.0(Mar 4, 2017)

    • Comments are now in the Apple preferred style.
    • syncUbiquitousKeyValueStoreOnChange replaces syncUbiquitousStoreKeyValueStoreOnChange.
      • This is only a name change. The Functionality remains the same.
    • Replaced Sample App with ZephyrExample.

    Note: These changes are for the master (Swift 3) branch only.

    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Sep 14, 2016)

  • 1.5.1(Apr 12, 2016)

  • 1.5.0(Mar 22, 2016)

  • 1.4.5(Feb 8, 2016)

  • 1.4.4(Feb 8, 2016)

  • 1.4.3(Dec 18, 2015)

  • 1.4.2(Dec 11, 2015)

    • Zephyr now synchronously processes incoming and outgoing changes to your monitoredKeys on a shared serial queue. (e.g., FIFO).
    • Bugfix to deinit method.
    • Stylistic changes

    Thanks to @vgritsenko for guidance in releasing this version.

    Source code(tar.gz)
    Source code(zip)
  • 1.4.1(Dec 1, 2015)

Owner
Arthur Ariel Sabintsev
Senior Engineering Manager
Arthur Ariel Sabintsev
Swifty and modern UserDefaults

Defaults Swifty and modern UserDefaults Store key-value pairs persistently across launches of your app. It uses NSUserDefaults underneath but exposes

Sindre Sorhus 1.3k Jan 6, 2023
Simple, Strongly Typed UserDefaults for iOS, macOS and tvOS

DefaultsKit leverages Swift 4's powerful Codable capabilities to provide a Simple and Strongly Typed wrapper on top of UserDefaults. It uses less than 70 lines of code to acomplish this.

Nuno Dias 1.4k Dec 26, 2022
Default is a Modern interface to UserDefaults + Codable support

Default is a library that extends what UserDefaults can do by providing extensions for saving custom objects that conform to Codable and also providing a new interface to UserDefaults described below, via the protocol DefaultStorable. You can use only the Codable support extensions or the DefaultStorable protocol extensions or both. (or none, that's cool too)

Nicholas Maccharoli 475 Dec 20, 2022
Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, configurations and app-state.

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

Eric Marchand 557 Nov 22, 2022
tl;dr You love Swift's Codable protocol and use it everywhere

tl;dr You love Swift's Codable protocol and use it everywhere, who doesn't! Here is an easy and very light way to store and retrieve -reasonable amoun

Omar Albeik 452 Oct 17, 2022
GenericLocalPersistence is a clean and easy-to-use code that is useful for integrating local storage

GenericLocalPersistence is a clean and easy-to-use code that is useful for integrating local storage like UserDefaults, PList, Keychain.

MindInventory 17 Sep 20, 2022
Effortlessly synchronize UserDefaults over iCloud.

Zephyr ??️ Effortlessly sync UserDefaults over iCloud About Zephyr synchronizes specific keys and/or all of your UserDefaults over iCloud using NSUbiq

Arthur Ariel Sabintsev 841 Dec 23, 2022
PGPro can encrypt and decrypt messages as well as manage all your OpenPGP keys. It is free, simple and lightweight. Everything stays on your device. PGPro is made in Switzerland.

PGPro can encrypt and decrypt messages as well as manage all your OpenPGP keys. It is free, simple and lightweight. Everything stays on your device. P

Luca Näf 250 Jan 4, 2023
iCloud Drive is Apple's essential connection between all your devices, Mac, iPhone, iPad, even your Windows PC.

iCloud Drive is Apple's essential connection between all your devices, Mac, iPhone, iPad, even your Windows PC.While the cost of storage seems expensive in comparison to other online storage services, its advantage is that it works natively across all your devices.

MindInventory 12 Jul 29, 2022
Mahmoud-Abdelwahab 5 Nov 23, 2022
Convenient domain specific language for writing programmatic UI built over UIKit and more.

XYKit Swifty and convenient domain specific language for creating programmatic UI in a more declarative way and more than that. Built on top of UIKit

Denis Goloborodko 1 Nov 5, 2021
SecureDefaults is a wrapper over UserDefaults/NSUserDefaults with an extra AES-256 encryption layer

SecureDefaults for iOS, macOS Requirements • Usage • Installation • Contributing • Acknowledgments • Contributing • Author • License SecureDefaults is

Victor Peschenkov 216 Dec 22, 2022
A lightweight wrapper over UserDefaults/NSUserDefaults with an additional layer of AES-256 encryption

SecureDefaults for iOS, macOS Requirements • Usage • Installation • Contributing • Acknowledgments • Contributing • Author • License SecureDefaults is

Victor Peschenkov 216 Dec 22, 2022
A Layer-2 framework built over Keychain API which helps in using Keychain in all your Apple devices with easiness and flexibility.

Keychain Manager Keychain Manager is a Layer-2 framework built over Keychain API which helps in using Keychain in all your Apple devices with easiness

Gokul Nair 14 Jan 1, 2023
Util for generation RSA keys on your client and save to keychain or convert into Data 🔑 🔐

RSASwiftGenerator ?? ?? To run the example project, clone the repo, and run pod install from the Example directory first. Requirements ⚠️ SWIFT 4 XCod

null 21 Apr 30, 2022
An iOS App to generate phonetic keys for your Chinese contacts. Written in Swift.

An iOS App to add phonetic keys with Pinyin for Chinese(SC & TC) names. Your Contacts will be sorted by alphabet automatically even under English System.

iAugus 595 Dec 27, 2022
In this mini app covered the concepts like basics of SwiftUI and Navigations and Animations and List with CRUD functions and MVVM and App Launch and App icons adding and also applied persistence using UserDefaults Concept.

TodoList In this application used the concepts from the beginner level project of SwiftUI_Evolve_1 The following concepts covered in this mini app Swi

Sivaram Yadav 2 Dec 4, 2021
Example of using TOTP with iCloud Keychain in iOS 15

Installation This example needs Ngrok and Ruby 3.0.3+. Setup project with Makefi

Makeeyaf 0 Dec 31, 2021
CloudKit, Apple’s remote data storage service, provides a possibility to store app data using users’ iCloud accounts as a back-end storage service.

CloudKit, Apple’s remote data storage service, provides a possibility to store app data using users’ iCloud accounts as a back-end storage service. He

Yalantis 252 Nov 4, 2022
iPhone and iPod Touch version of Skeleton Key: is an addictive and unique puzzle game in which you shift keys around the board unlocking treasure chests. Made with cocos2d-iphone.

Skeleton Key (iOS) Skeleton Key is an addictive and unique puzzle game in which you shift keys around the board unlocking treasure chests. It's availa

null 117 Jun 6, 2022