Skip to content

Commit

Permalink
Updated documentation and prepared for 0.2.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt Comi authored and Matt Comi committed Apr 12, 2016
1 parent 8256817 commit 1f2c9fc
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 25 deletions.
10 changes: 9 additions & 1 deletion PersistentObject/PersistentObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ public class PersistentObject<ObjectType> {
/// Initializes the `PersistentObject` with the specified strategy.
///
/// - parameter strategy: The `PersistenceStrategy`.
/// - returns: The new `PersistentObject` instance.
public init<StrategyType:Strategy where ObjectType == StrategyType.ObjectType>(strategy: StrategyType) {
self.strategy = AnyStrategy(strategy: strategy)
object = strategy.unarchiveObject()
Expand Down Expand Up @@ -47,3 +46,12 @@ public class PersistentObject<ObjectType> {
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))
}
}
4 changes: 2 additions & 2 deletions PersistentObject/Strategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
38 changes: 26 additions & 12 deletions PersistentObject/UbiquituousKeyValueStoreStrategy.swift
Original file line number Diff line number Diff line change
@@ -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<ObjectType>(strategy: UbiquituousKeyValueStoreStrategy<ObjectType>)
}

Expand All @@ -13,10 +17,11 @@ public class UbiquituousKeyValueStoreStrategy<ObjectType:NSCoding> : 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,
Expand All @@ -40,23 +45,33 @@ public class UbiquituousKeyValueStoreStrategy<ObjectType:NSCoding> : 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`.
public func synchronize() {
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
Expand All @@ -71,12 +86,11 @@ public class UbiquituousKeyValueStoreStrategy<ObjectType:NSCoding> : 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)
}
Expand Down
1 change: 0 additions & 1 deletion PersistentObject/UserDefaultsStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ public class UserDefaultsStrategy<ObjectType:NSCoding> : 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
Expand Down
14 changes: 5 additions & 9 deletions PersistentObjectTests/PersistentObjectTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ 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]
}

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()
Expand Down Expand Up @@ -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<Person>(filename: filename)

let person = PersistentObject<Person>(strategy: strategy)
Expand Down
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<Person>(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<Person>(strategy: FileStrategy(filename: "file.data"))
```

This example persists the `Person` to the NSUbiquitousKeyValueStore.

```swift
let strategy = UbiquituousKeyValueStoreStrategy<Person>(key: "person")
strategy.delegate = self

let persistentPerson = PersistentObject<Person>(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.

0 comments on commit 1f2c9fc

Please sign in to comment.