From 1f2c9fc59e3aa80cd35587cc120bb111daa51a3f Mon Sep 17 00:00:00 2001 From: Matt Comi Date: Tue, 12 Apr 2016 10:12:53 +0800 Subject: [PATCH] Updated documentation and prepared for 0.2.0. --- PersistentObject/PersistentObject.swift | 10 +++- PersistentObject/Strategy.swift | 4 +- .../UbiquituousKeyValueStoreStrategy.swift | 38 ++++++++----- PersistentObject/UserDefaultsStrategy.swift | 1 - .../PersistentObjectTests.swift | 14 ++--- README.md | 53 +++++++++++++++++++ 6 files changed, 95 insertions(+), 25 deletions(-) diff --git a/PersistentObject/PersistentObject.swift b/PersistentObject/PersistentObject.swift index ecb8811..279a191 100644 --- a/PersistentObject/PersistentObject.swift +++ b/PersistentObject/PersistentObject.swift @@ -10,7 +10,6 @@ public class PersistentObject { /// Initializes the `PersistentObject` with the specified strategy. /// /// - parameter strategy: The `PersistenceStrategy`. - /// - returns: The new `PersistentObject` instance. public init(strategy: StrategyType) { self.strategy = AnyStrategy(strategy: strategy) object = strategy.unarchiveObject() @@ -47,3 +46,12 @@ public class PersistentObject { save() } } + +public extension PersistentObject where ObjectType:NSCoding { + /// Initializes the `PersistentObject` with the `UserDefaults` strategy. + /// + /// - parameter key: The key to associate with this object. + public convenience init(key: String) { + self.init(strategy: UserDefaultsStrategy(key: key)) + } +} \ No newline at end of file diff --git a/PersistentObject/Strategy.swift b/PersistentObject/Strategy.swift index 08ad1bd..46d2616 100644 --- a/PersistentObject/Strategy.swift +++ b/PersistentObject/Strategy.swift @@ -6,12 +6,12 @@ public protocol Strategy { /// Archives an object. /// - /// parameter object: The object to archive. + /// - parameter object: The object to archive. func archiveObject(object: ObjectType?) /// Unarchives an object. /// - /// returns: The unarchived object. + /// - returns: The unarchived object. func unarchiveObject() -> ObjectType? /// Performs any necessary synchronization. diff --git a/PersistentObject/UbiquituousKeyValueStoreStrategy.swift b/PersistentObject/UbiquituousKeyValueStoreStrategy.swift index 31a5340..2c36002 100644 --- a/PersistentObject/UbiquituousKeyValueStoreStrategy.swift +++ b/PersistentObject/UbiquituousKeyValueStoreStrategy.swift @@ -1,6 +1,10 @@ // Copyright © 2016 Matt Comi. All rights reserved. +/// A delegate of the `UbiquituousKeyValueStoreStrategy`. public protocol UbiquituousKeyValueStoreDelegate { + /// Called when the object changed externally. + /// + /// - parameter strategy: The object's strategy. func objectChangedExternally(strategy: UbiquituousKeyValueStoreStrategy) } @@ -13,10 +17,11 @@ public class UbiquituousKeyValueStoreStrategy : Strategy { /// Initializes the `UbiquituousKeyValueStoreStrategy` with the specified key. /// - /// - parameter key: The key to associate with this object. - /// - returns: The new `UbiquituousKeyValueStoreStrategy` instance. - public init(key: String) { + /// - parameter key: The key to associate with this object. + /// - parameter delegate: The delegate. Default is `nil`. + public init(key: String, delegate: UbiquituousKeyValueStoreDelegate? = nil) { self.key = key + self.delegate = delegate NSNotificationCenter.defaultCenter().addObserver( self, @@ -40,16 +45,11 @@ public class UbiquituousKeyValueStoreStrategy : Strategy { } } - /// Unarchives an object from the `NSUbiquituousKeyValueStore` database. + /// Unarchives an object from the `NSUbiquituousKeyValueStore` database and synchronizes. /// /// - returns: The unarchived object. public func unarchiveObject() -> ObjectType? { - let store = NSUbiquitousKeyValueStore.defaultStore() - if let data = store.dataForKey(key) { - return NSKeyedUnarchiver.unarchiveObjectWithData(data) as? ObjectType - } - - return nil + return unarchiveObject(synchronize: true) } /// Synchronizes the `NSUbiquituousKeyValueStore`. @@ -57,6 +57,21 @@ public class UbiquituousKeyValueStoreStrategy : Strategy { NSUbiquitousKeyValueStore.defaultStore().synchronize() } + private func unarchiveObject(synchronize synchronize: Bool) -> ObjectType? { + var object: ObjectType? = nil + + let store = NSUbiquitousKeyValueStore.defaultStore() + if let data = store.dataForKey(key) { + object = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? ObjectType + } + + if synchronize { + store.synchronize() + } + + return object + } + @objc private func ubiquitousKeyValueStoreDidChangeExternally(notification: NSNotification) { guard let userInfo = notification.userInfo else { return @@ -71,12 +86,11 @@ public class UbiquituousKeyValueStoreStrategy : Strategy { } guard let keys = userInfo[NSUbiquitousKeyValueStoreChangedKeysKey] as? [String] else { - print(userInfo[NSUbiquitousKeyValueStoreChangedKeysKey]) return } if keys.contains(key) { - self.unarchiveObject() + self.unarchiveObject(synchronize: false) self.delegate?.objectChangedExternally(self) } diff --git a/PersistentObject/UserDefaultsStrategy.swift b/PersistentObject/UserDefaultsStrategy.swift index bb762bb..bfc540d 100644 --- a/PersistentObject/UserDefaultsStrategy.swift +++ b/PersistentObject/UserDefaultsStrategy.swift @@ -9,7 +9,6 @@ public class UserDefaultsStrategy : Strategy { /// /// - parameter key: The key to associate with this object. /// - parameter userDefaults: The `NSUserDefaults` database. Defaults to `NSUserDefaults.standardUserDefaults()`. - /// - returns: The new `UserDefaultsStrategy` instance. public init(key: String, userDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()) { self.key = key self.userDefaults = userDefaults diff --git a/PersistentObjectTests/PersistentObjectTests.swift b/PersistentObjectTests/PersistentObjectTests.swift index 74df4ba..a52264f 100644 --- a/PersistentObjectTests/PersistentObjectTests.swift +++ b/PersistentObjectTests/PersistentObjectTests.swift @@ -43,7 +43,7 @@ func ==(lhs: Person, rhs: Person) -> Bool { return lhs.name == rhs.name && lhs.age == rhs.age } -func documentsDirectory() -> NSURL { +func documentDirectory() -> NSURL { return NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] } @@ -51,7 +51,7 @@ class PersistentObjectTests: XCTestCase { let personKey = "person" let dateKey = "date" - let filename = documentsDirectory().URLByAppendingPathComponent("test.data").path! + let filename = documentDirectory().URLByAppendingPathComponent("test.data").path! override func setUp() { super.setUp() @@ -120,16 +120,12 @@ class PersistentObjectTests: XCTestCase { } func testFile() { - do { - try NSFileManager.defaultManager().createDirectoryAtURL( - documentsDirectory(), + // The documentDirectory doesn't exist on travis-ci so create it. + _ = try? NSFileManager.defaultManager().createDirectoryAtURL( + documentDirectory(), withIntermediateDirectories: true, attributes: nil) - } catch { - } - print(documentsDirectory()) - print(filename) let strategy = FileStrategy(filename: filename) let person = PersistentObject(strategy: strategy) diff --git a/README.md b/README.md index 571763c..b862521 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,56 @@ ![](https://img.shields.io/cocoapods/v/PersistentObject.svg?style=flat) Simplifies object persistence in Swift. + +Include support for `NSUserDefaults`, `NSUbiquitousKeyValueStore` and the file system. + +## Usage + +To persist an NSCoding-compliant object to the `NSUserDefaults` database, specify its key. + +```swift +let persistentPerson = PersistentObject(key: "person") +``` + +If an object with the specified key has been persisted previously, it will be unarchived from `NSUserDefaults` and initialized. If not, you will need to initialize it yourself. + +```swift +if persistentPerson.object == nil { + persistentPerson.reset(Person(name: "Brian Doyle-Murray")) +} +``` + +The underlying object may be accessed with the `object` property. + +```swift +persistentPerson.object?.age = 70 +``` + +The object is automatically archived back to `NSUserDefaults` when the application enters the background and when the `PersistentObject` is deinitialized. It may also be triggered manually: + +```swift +persistentPerson.save() +``` + +## Strategies + +You may specify *how* an object is persisted by specifying its `Strategy`. In this example, the `Person` is persisted to a file named `file.data`. + +```swift +let persistentPerson = PersistentObject(strategy: FileStrategy(filename: "file.data")) +``` + +This example persists the `Person` to the NSUbiquitousKeyValueStore. + +```swift +let strategy = UbiquituousKeyValueStoreStrategy(key: "person") +strategy.delegate = self + +let persistentPerson = PersistentObject(strategy: strategy) +``` + +Note `strategy.delegate = self`. Delegates of the `UbiquituousKeyValueStoreStrategy` are notified when the object changes externally. + +## Custom Strategies + +You may implement the `Strategy` protocol to provide alternative persistence strategies. \ No newline at end of file