updated documentation (in progress)

This commit is contained in:
John Rommel Estropia
2015-07-14 07:44:45 +09:00
parent e7bcb501fd
commit 858dd0962d
6 changed files with 102 additions and 55 deletions

View File

@@ -31,6 +31,12 @@ import CoreData
public extension NSManagedObject {
/**
Provides a convenience wrapper for accessing `primitiveValueForKey(...)` with proper calls to `willAccessValueForKey(...)` and `didAccessValueForKey(...)`. This is useful when implementing accessor methods for transient attributes.
- parameter KVCKey: the KVC key
- returns: the primitive value for the KVC key
*/
public func accessValueForKVCKey(KVCKey: KeyPath) -> AnyObject? {
self.willAccessValueForKey(KVCKey)
@@ -40,6 +46,12 @@ public extension NSManagedObject {
return primitiveValue
}
/**
Provides a convenience wrapper for setting `setPrimitiveValue(...)` with proper calls to `willChangeValueForKey(...)` and `didChangeValueForKey(...)`. This is useful when implementing mutator methods for transient attributes.
- parameter value: the value to set the KVC key with
- parameter KVCKey: the KVC key
*/
public func setValue(value: AnyObject?, forKVCKey KVCKey: KeyPath) {
self.willChangeValueForKey(KVCKey)

View File

@@ -33,6 +33,10 @@ public extension NSProgress {
// MARK: Public
/**
Sets a closure that the `NSProgress` calls whenever its `fractionCompleted` changes. You can use this instead of setting up KVO.
- parameter closure: the closure to execute on progress change
*/
public func setProgressHandler(closure: ((progress: NSProgress) -> Void)?) {
self.progressObserver.progressHandler = closure

View File

@@ -251,6 +251,7 @@ internal extension NSManagedObjectContext {
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .ManagedObjectResultType
fetchRequest.returnsObjectsAsFaults = true
fetchRequest.includesPropertyValues = false
for clause in deleteClauses {

View File

@@ -32,7 +32,7 @@ import CoreData
/**
A `MigrationChain` indicates the sequence of model versions to be used as the order for incremental migration. This is typically passed to the `DataStack` initializer and will be applied to all stores added to the `DataStack` with `addSQLiteStore(...)` and its variants.
Initializing with empty values (either `nil`, `[]`, or `[:]`) signifies to use the .xcdatamodel's current version as the final version, and to disable incremental migrations:
Initializing with empty values (either `nil`, `[]`, or `[:]`) instructs the `DataStack` to use the .xcdatamodel's current version as the final version, and to disable incremental migrations:
let dataStack = DataStack(migrationChain: nil)
@@ -151,8 +151,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
self.versionTree = versionTree
self.rootVersions = Set(versionTree.keys).subtract(versionTree.values)
self.leafVersions = leafVersions
self.valid = valid
&& Set(versionTree.keys).union(versionTree.values).filter { isVersionAmbiguous($0) }.count <= 0
self.valid = valid && Set(versionTree.keys).union(versionTree.values).filter { isVersionAmbiguous($0) }.count <= 0
}

View File

@@ -137,12 +137,12 @@ public enum MigrationResult {
// MARK: Public
/**
`MigrationResult.Success` indicates that the `commit()` for the transaction succeeded, either because the save succeeded or because there were no changes to save. The associated value `hasChanges` indicates if there were saved changes or not.
`MigrationResult.Success` indicates either the migration succeeded, or there were no migrations needed. The associated value is an array of `MigrationType`s reflecting the migration steps completed.
*/
case Success([MigrationType])
/**
`SaveResult.Failure` indicates that the `commit()` for the transaction failed. The associated object for this value is the related `NSError` instance.
`SaveResult.Failure` indicates that the migration failed. The associated object for this value is the related `NSError` instance.
*/
case Failure(NSError)
@@ -166,9 +166,7 @@ public enum MigrationResult {
internal init(_ errorCode: CoreStoreErrorCode, userInfo: [NSObject: AnyObject]?) {
self.init(NSError(
coreStoreErrorCode: errorCode,
userInfo: userInfo))
self.init(NSError(coreStoreErrorCode: errorCode, userInfo: userInfo))
}
}

127
README.md
View File

@@ -9,23 +9,46 @@ Unleashing the real power of Core Data with the elegance and safety of Swift
[Click here for a wiki version of this README](https://github.com/JohnEstropia/CoreStore/wiki)
[Upgrading from 0.2.0 to 1.0.0](#changes-from-v020-to-100)
## Another Core Data wrapper?
## Contents
I have used (and abused) Core Data for almost 5 years. While the majority of Core Data wrappers serve their purpose really well (I worked with [MagicalRecord](https://github.com/magicalpanda/MagicalRecord) for a looong time), I have always felt that they "wrap" too much of the Core Data SDK's functionality.
For example:
- a lot of iOS devs have never used (or heard of) "Configurations"
- very few are aware that entities can be saved in separate *sqlite* files to boost performance and reduce data corruption
- we're forced to name our `NSManagedObject` subclasses exactly the same as our Entities
- and so on...
I wrote this library when Swift was made public, and CoreStore is now a powerhouse with functionalities rarely implemented in other Core Data libraries.
- [What CoreStore does better](#what-corestore-does-better)
- [TL;DR (a.k.a. sample codes)](#tldr-aka-sample-codes)
- [Architecture](#architecture)
- CoreStore Tutorials (All of these have demos in the **CoreStoreDemo** app project!)
- [Setting up](#setting-up)
- [Migrations](#migrations)
- [Incremental migrations](#incremental-migrations)
- [Saving and processing transactions](#saving-and-processing-transactions)
- [Transaction types](#transaction-types)
- [Asynchronous transactions](#asynchronous-transactions)
- [Synchronous transactions](#synchronous-transactions)
- [Detached transactions](#detached-transactions)
- [Creating objects](#creating-objects)
- [Updating objects](#updating-objects)
- [Deleting objects](#deleting-objects)
- [Fetching and querying](#fetching-and-querying)
- [`From` clause](#from-clause)
- [Fetching](#fetching)
- [`Where` clause](#where-clause)
- [`OrderBy` clause](#orderby-clause)
- [`Tweak` clause](#tweak-clause)
- [Querying](#querying)
- [`Select<T>` clause](#selectt-clause)
- [`GroupBy` clause](#groupby-clause)
- [Logging and error handling](#logging-and-error-handling)
- [Observing changes and notifications](#observing-changes-and-notifications)
- [Observe a single object](#observe-a-single-object)
- [Observe a list of objects](#observe-a-list-of-objects)
- [Roadmap](#roadmap)
- [Installation](#installation)
- [Changesets](#changesets)
- [Upgrading from v0.2.0 to 1.0.0](#upgrading-from-v020-to-100)
### What CoreStore does better:
## What CoreStore does better:
- Heavily supports multiple persistent stores per data stack, just the way *.xcdatamodeld* files are designed to. CoreStore will also manage one data stack by default, but you can create and manage as many as you need.
- Ability to plug-in your own logging framework
@@ -39,19 +62,33 @@ I wrote this library when Swift was made public, and CoreStore is now a powerhou
**CoreStore's goal is not to expose shorter, magical syntax, but to provide an API that focuses on readability, consistency, and safety.**
## TL;DR (a.k.a. sample codes)
Quick-setup:
Setting-up with incremental migration support:
```swift
CoreStore.defaultStack = DataStack(
modelName: "MyStore",
migrationChain: ["MyStore", "MyStoreV2", "MyStoreV3"]
)
```
Adding a store:
```swift
do {
try CoreStore.addSQLiteStoreAndWait(fileName: "MyStore.sqlite")
try CoreStore.addSQLiteStore(
fileName: "MyStore.sqlite",
completion: { (result) -> Void in
// ...
}
)
}
catch {
// ...
}
```
Simple transactions:
Starting transactions:
```swift
CoreStore.beginAsynchronous { (transaction) -> Void in
let person = transaction.create(Into(MyPersonEntity))
@@ -67,7 +104,7 @@ CoreStore.beginAsynchronous { (transaction) -> Void in
}
```
Easy fetching:
Fetching objects:
```swift
let people = CoreStore.fetchAll(From(MyPersonEntity))
```
@@ -82,7 +119,7 @@ let people = CoreStore.fetchAll(
)
```
Simple queries:
Querying values:
```swift
let maxAge = CoreStore.queryValue(
From(MyPersonEntity),
@@ -95,20 +132,6 @@ But really, there's a reason I wrote this huge README. Read up on the details!
Check out the **CoreStoreDemo** app project for sample codes as well!
## Contents
- Tutorials
- [Architecture](#architecture)
- [Setting up](#setup)
- [Saving and processing transactions](#transactions)
- [Fetching and querying](#fetch_query)
- [Logging and error handling](#logging)
- [Observing changes and notifications](#observing)
- [Roadmap](#roadmap)
- [Installation](#installation)
(All of these have demos in the **CoreStoreDemo** app project!)
## Architecture
For maximum safety and performance, CoreStore will enforce coding patterns and practices it was designed for. (Don't worry, it's not as scary as it sounds.) But it is advisable to understand the "magic" of CoreStore before you use it in your apps.
@@ -217,6 +240,13 @@ class MyViewController: UIViewController {
```
## Migrations
<README pending>
### Incremental migrations
<README pending>
## Saving and processing transactions
To ensure deterministic state for objects in the read-only `NSManagedObjectContext`, CoreStore does not expose API's for updating and saving directly from the main context (or any other context for that matter.) Instead, you spawn *transactions* from `DataStack` instances:
@@ -236,7 +266,7 @@ CoreStore.beginAsynchronous { (transaction) -> Void in
```
The `commit()` method saves the changes to the persistent store. If `commit()` is not called when the transaction block completes, all changes within the transaction is discarded.
The examples above use `beginAsynchronous(...)`, but there are actually 3 types of transactions at you disposal: *asynchronous*, *synchronous*, and *detached*.
The examples above use `beginAsynchronous(...)`, but there are actually 3 types of transactions at your disposal: *asynchronous*, *synchronous*, and *detached*.
### Transaction types
@@ -329,7 +359,7 @@ CoreStore.beginAsynchronous { (transaction) -> Void in
transaction.commit()
}
```
*(For more about fetching, read [Fetching and querying](#fetch_query))*
*(For more about fetching, see [Fetching and querying](#fetching-and-querying))*
**Do not update an instance that was not created/fetched from the transaction.** If you have a reference to the object already, use the transaction's `edit(...)` method to get an editable proxy instance for that object:
```swift
@@ -810,22 +840,8 @@ let person2 = self.monitor[1, 2]
// person1 and person2 are the same object
```
# Changes from v0.2.0 to 1.0.0
- Renamed some classes/protocols to shorter, more relevant, easier to remember names:
- `ManagedObjectController` to `ObjectMonitor`
- `ManagedObjectObserver` to `ObjectObserver`
- `ManagedObjectListController` to `ListMonitor`
- `ManagedObjectListChangeObserver` to `ListObserver`
- `ManagedObjectListObjectObserver` to `ListObjectObserver`
- `ManagedObjectListSectionObserver` to `ListSectionObserver`
- `SectionedBy` to `SectionBy` (match tense with `OrderBy` and `GroupBy`)
The protocols above had their methods renamed as well, to retain the natural language semantics.
- New migration utilities! (README still pending) Check out *DataStack+Migration.swift* and *CoreStore+Migration.swift* for the new methods.
# Roadmap
- Migration utilities (In progress!)
- Swift 2.0 syntax (In progress!)
- Data importing utilities for transactions
- Support iCloud stores
@@ -860,6 +876,23 @@ Drag and drop **CoreStore.xcodeproj** to your project.
#### To include directly in your app module:
Add all *.swift* files to your project.
# Changesets
## Upgrading from v0.2.0 to 1.0.0
- Renamed some classes/protocols to shorter, more relevant, easier to remember names:
- `ManagedObjectController` to `ObjectMonitor`
- `ManagedObjectObserver` to `ObjectObserver`
- `ManagedObjectListController` to `ListMonitor`
- `ManagedObjectListChangeObserver` to `ListObserver`
- `ManagedObjectListObjectObserver` to `ListObjectObserver`
- `ManagedObjectListSectionObserver` to `ListSectionObserver`
- `SectionedBy` to `SectionBy` (match tense with `OrderBy` and `GroupBy`)
The protocols above had their methods renamed as well, to retain the natural language semantics.
- Several methods now `throw` errors insted of returning a result `enum`.
- New migration utilities! (README still pending) Check out *DataStack+Migration.swift* and *CoreStore+Migration.swift* for the new methods, as well as *DataStack.swift* for its new initializer.
# Contributions
While CoreStore's design is pretty solid and the unit test and demo app work well, CoreStore is pretty much still in its early stage. With more exposure to production code usage and criticisms from the developer community, CoreStore hopes to mature as well.
Please feel free to report any issues, suggestions, or criticisms!