Compare commits

..

22 Commits
1.5.0 ... 1.5.4

Author SHA1 Message Date
John Estropia
928585029d XCode 7.3 full support 2016-03-23 12:39:11 +09:00
John Estropia
dc6d22b6ff updated travis XCode version 2016-03-23 12:14:34 +09:00
John Estropia
5ca0f657cb XCode 7.3 fixes 2016-03-23 12:07:31 +09:00
John Rommel Estropia
c323a28c19 fix warnings in demo app 2016-03-12 09:27:59 +09:00
John Estropia
64ad7b3bfd Update README.md 2016-03-11 20:59:52 +09:00
John Estropia
df441c5d04 Update README.md 2016-03-11 20:58:33 +09:00
John Estropia
3c2fb28644 added Packaged.swift 2016-03-01 19:42:28 +09:00
John Estropia
e66a13632a Merge branch 'develop' 2016-02-25 15:52:59 +09:00
John Estropia
4c78a309bc deprecated NSFetchedResultsController initializer in favor of static factory method 2016-02-25 15:52:49 +09:00
John Estropia
9055daa58c Merge branch 'develop' 2016-02-25 15:11:40 +09:00
John Estropia
3905423038 fix compile error 2016-02-25 15:05:27 +09:00
John Estropia
15353268e2 Allow unsafe transactions to save synchronously 2016-02-25 15:04:05 +09:00
John Estropia
c12331f403 Merge pull request #53 from mpurbo/patch-1
added missing closing bracket on sample code.
2016-02-22 22:26:38 +09:00
Mamad Purbo
a55a8d389c added missing closing bracket on sample code. 2016-02-22 11:50:28 +09:00
John Rommel Estropia
6e88b14237 fixed readme build status 2016-02-20 12:30:02 +09:00
John Rommel Estropia
53700a267f version bump 2016-02-20 12:28:39 +09:00
John Rommel Estropia
6c95b010e9 utility to update an existing ImportableObject from its ImportSource (fixes #52) 2016-02-20 12:26:23 +09:00
John Rommel Estropia
1af675e8b7 tidy up 2016-02-20 12:05:01 +09:00
John Rommel Estropia
b85f16cf68 Merge branch 'master' into develop 2016-02-20 01:25:40 +09:00
John Estropia
37bf4179c8 renamed "Incremental Migrations" to "Progressive Migrations" to match the common term used by the community 2016-02-17 15:34:33 +09:00
John Estropia
240dda6ad6 Merge pull request #50 from ReadmeCritic/master
Correct the spelling of Xcode in README
2016-02-17 10:03:47 +09:00
ReadmeCritic
ffe73d0f66 Correct the spelling of Xcode in README 2016-02-16 11:47:36 -08:00
27 changed files with 321 additions and 87 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ CoreStoreDemo/CoreStoreDemo.xcodeproj/xcuserdata
Carthage/Build
CoreStore.xcworkspace/xcuserdata
.DS_Store
DerivedData

View File

@@ -1,5 +1,5 @@
language: objective-c
osx_image: xcode7.2
osx_image: xcode7.3
sudo: false
git:
submodules: false
@@ -10,15 +10,15 @@ env:
- LC_CTYPE=en_US.UTF-8
- LANG=en_US.UTF-8
matrix:
- DESTINATION="OS=9.2,name=iPhone 6s" SCHEME="CoreStore iOS" SDK=iphonesimulator9.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator9.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator9.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.2,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator9.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.2 RUN_TESTS="YES" POD_LINT="YES"
- DESTINATION="OS=9.3,name=iPhone 6s" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.2,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES"
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.11 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=2.1,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator2.1 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=9.1,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator9.1 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator2.2 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator9.2 RUN_TESTS="YES" POD_LINT="NO"
before_install:
- gem install cocoapods --no-rdoc --no-ri --no-document --quiet
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
@@ -35,8 +35,8 @@ script:
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
fi
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.2" -destination "OS=9.2,name=iPhone 6s" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.2" -destination "OS=9.2,name=iPhone 6s" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- if [ $POD_LINT == "YES" ]; then
pod lib lint --quick;
fi

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "1.5.0"
s.version = "1.5.4"
s.license = "MIT"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore"
@@ -18,5 +18,5 @@ Pod::Spec.new do |s|
s.requires_arc = true
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-D USE_FRAMEWORKS' }
s.dependency "GCDKit", "1.1.7"
s.dependency "GCDKit", "1.2.1"
end

View File

@@ -1 +1 @@
github "JohnEstropia/GCDKit" == 1.1.7
github "JohnEstropia/GCDKit" == 1.2.1

View File

@@ -34,7 +34,7 @@ public extension NSFetchedResultsController {
/**
Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful to partially support Objective-C classes by passing an `NSFetchedResultsController` instance instead of a `ListMonitor`.
*/
public func createForStack<T: NSManagedObject>(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController {
public static func createForStack<T: NSManagedObject>(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController {
return CoreStoreFetchedResultsController<T>(
context: dataStack.mainContext,
@@ -45,10 +45,41 @@ public extension NSFetchedResultsController {
)
}
@available(*, deprecated=1.5.2, message="Use NSFetchedResultsController.createForStack(_:fetchRequest:from:sectionBy:fetchClauses:) to create NSFetchedResultsControllers directly")
public convenience init<T: NSManagedObject>(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) {
let context = dataStack.mainContext
from?.applyToFetchRequest(fetchRequest, context: context, applyAffectedStores: false)
for clause in fetchClauses {
clause.applyToFetchRequest(fetchRequest)
}
if let from = from {
from.applyAffectedStoresForFetchedRequest(fetchRequest, context: context)
}
else {
guard let from = (fetchRequest.entity.flatMap { $0.managedObjectClassName }).flatMap(NSClassFromString).flatMap(From.init) else {
fatalError("Attempted to create an \(typeName(NSFetchedResultsController)) without a From clause or an NSEntityDescription.")
}
from.applyAffectedStoresForFetchedRequest(fetchRequest, context: context)
}
self.init(
fetchRequest: fetchRequest,
managedObjectContext: context,
sectionNameKeyPath: sectionBy?.sectionKeyPath,
cacheName: nil
)
}
// MARK: Internal
internal func createFromContext<T: NSManagedObject>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController {
internal static func createFromContext<T: NSManagedObject>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController {
return CoreStoreFetchedResultsController<T>(
context: context,

View File

@@ -106,81 +106,193 @@ public struct From<T: NSManagedObject> {
self.init(entityClass: T.self, configurations: configurations)
}
/**
Initializes a `From` clause with the specified configurations.
Sample Usage:
```
let people = transaction.fetchAll(From(MyPersonEntity.self, nil, "Configuration1"))
```
- parameter entity: the associated `NSManagedObject` type
- parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
- parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter)
*/
public init(_ entity: T.Type, _ configuration: String?, _ otherConfigurations: String?...) {
self.init(entityClass: entity, configurations: [configuration] + otherConfigurations)
}
/**
Initializes a `From` clause with the specified configurations.
Sample Usage:
```
let people = transaction.fetchAll(From(MyPersonEntity.self, ["Configuration1", "Configuration1"]))
```
- parameter entity: the associated `NSManagedObject` type
- parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
*/
public init(_ entity: T.Type, _ configurations: [String?]) {
self.init(entityClass: entity, configurations: configurations)
}
/**
Initializes a `From` clause with the specified configurations.
Sample Usage:
```
let people = transaction.fetchAll(From(MyPersonEntity.self, nil, "Configuration1"))
```
- parameter entity: the associated `NSManagedObject` entity class
- parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
- parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter)
*/
public init(_ entityClass: AnyClass, _ configuration: String?, _ otherConfigurations: String?...) {
self.init(entityClass: entityClass, configurations: [configuration] + otherConfigurations)
}
/**
Initializes a `From` clause with the specified configurations.
Sample Usage:
```
let people = transaction.fetchAll(From(MyPersonEntity.self, ["Configuration1", "Configuration1"]))
```
- parameter entity: the associated `NSManagedObject` entity class
- parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
*/
public init(_ entityClass: AnyClass, _ configurations: [String?]) {
self.init(entityClass: entityClass, configurations: configurations)
}
/**
Initializes a `From` clause with the specified store URLs.
- parameter storeURL: the persistent store URL to associate objects from.
- parameter otherStoreURLs: an optional list of other persistent store URLs to associate objects from (see `storeURL` parameter)
*/
public init(_ storeURL: NSURL, _ otherStoreURLs: NSURL...) {
self.init(entityClass: T.self, storeURLs: [storeURL] + otherStoreURLs)
}
/**
Initializes a `From` clause with the specified store URLs.
- parameter storeURLs: the persistent store URLs to associate objects from.
*/
public init(_ storeURLs: [NSURL]) {
self.init(entityClass: T.self, storeURLs: storeURLs)
}
/**
Initializes a `From` clause with the specified store URLs.
- parameter entity: the associated `NSManagedObject` type
- parameter storeURL: the persistent store URL to associate objects from.
- parameter otherStoreURLs: an optional list of other persistent store URLs to associate objects from (see `storeURL` parameter)
*/
public init(_ entity: T.Type, _ storeURL: NSURL, _ otherStoreURLs: NSURL...) {
self.init(entityClass: entity, storeURLs: [storeURL] + otherStoreURLs)
}
/**
Initializes a `From` clause with the specified store URLs.
- parameter entity: the associated `NSManagedObject` type
- parameter storeURLs: the persistent store URLs to associate objects from.
*/
public init(_ entity: T.Type, _ storeURLs: [NSURL]) {
self.init(entityClass: entity, storeURLs: storeURLs)
}
/**
Initializes a `From` clause with the specified store URLs.
- parameter entity: the associated `NSManagedObject` entity class
- parameter storeURL: the persistent store URL to associate objects from.
- parameter otherStoreURLs: an optional list of other persistent store URLs to associate objects from (see `storeURL` parameter)
*/
public init(_ entityClass: AnyClass, _ storeURL: NSURL, _ otherStoreURLs: NSURL...) {
self.init(entityClass: entityClass, storeURLs: [storeURL] + otherStoreURLs)
}
/**
Initializes a `From` clause with the specified store URLs.
- parameter entity: the associated `NSManagedObject` entity class
- parameter storeURLs: the persistent store URLs to associate objects from.
*/
public init(_ entityClass: AnyClass, _ storeURLs: [NSURL]) {
self.init(entityClass: entityClass, storeURLs: storeURLs)
}
/**
Initializes a `From` clause with the specified `NSPersistentStore`s.
- parameter persistentStore: the `NSPersistentStore` to associate objects from.
- parameter otherPersistentStores: an optional list of other `NSPersistentStore`s to associate objects from (see `persistentStore` parameter)
*/
public init(_ persistentStore: NSPersistentStore, _ otherPersistentStores: NSPersistentStore...) {
self.init(entityClass: T.self, persistentStores: [persistentStore] + otherPersistentStores)
}
/**
Initializes a `From` clause with the specified `NSPersistentStore`s.
- parameter persistentStores: the `NSPersistentStore`s to associate objects from.
*/
public init(_ persistentStores: [NSPersistentStore]) {
self.init(entityClass: T.self, persistentStores: persistentStores)
}
/**
Initializes a `From` clause with the specified `NSPersistentStore`s.
- parameter entity: the associated `NSManagedObject` type
- parameter persistentStore: the `NSPersistentStore` to associate objects from.
- parameter otherPersistentStores: an optional list of other `NSPersistentStore`s to associate objects from (see `persistentStore` parameter)
*/
public init(_ entity: T.Type, _ persistentStore: NSPersistentStore, _ otherPersistentStores: NSPersistentStore...) {
self.init(entityClass: entity, persistentStores: [persistentStore] + otherPersistentStores)
}
/**
Initializes a `From` clause with the specified `NSPersistentStore`s.
- parameter entity: the associated `NSManagedObject` type
- parameter persistentStores: the `NSPersistentStore`s to associate objects from.
*/
public init(_ entity: T.Type, _ persistentStores: [NSPersistentStore]) {
self.init(entityClass: entity, persistentStores: persistentStores)
}
/**
Initializes a `From` clause with the specified `NSPersistentStore`s.
- parameter entity: the associated `NSManagedObject` entity class
- parameter persistentStore: the `NSPersistentStore` to associate objects from.
- parameter otherPersistentStores: an optional list of other `NSPersistentStore`s to associate objects from (see `persistentStore` parameter)
*/
public init(_ entityClass: AnyClass, _ persistentStore: NSPersistentStore, _ otherPersistentStores: NSPersistentStore...) {
self.init(entityClass: entityClass, persistentStores: [persistentStore] + otherPersistentStores)
}
/**
Initializes a `From` clause with the specified `NSPersistentStore`s.
- parameter entity: the associated `NSManagedObject` entity class
- parameter persistentStores: the `NSPersistentStore`s to associate objects from.
*/
public init(_ entityClass: AnyClass, _ persistentStores: [NSPersistentStore]) {
self.init(entityClass: entityClass, persistentStores: persistentStores)

View File

@@ -60,6 +60,32 @@ public extension BaseDataTransaction {
}
}
/**
Updates an existing `ImportableObject` by importing values from the specified import source.
- parameter object: the `NSManagedObject` to update
- parameter source: the object to import values from
*/
public func importObject<T where T: NSManagedObject, T: ImportableObject>(
object: T,
source: T.ImportSource) throws {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(typeName(object)) outside the transaction's designated queue."
)
try autoreleasepool {
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
return
}
try object.didInsertFromImportSource(source, inTransaction: self)
}
}
/**
Creates multiple `ImportableObject`s by importing from the specified array of import sources.

View File

@@ -53,7 +53,7 @@ public protocol ImportableObject: class {
/**
The data type for the import source. This is most commonly an `NSDictionary` or another external source such as an `NSUserDefaults`.
*/
typealias ImportSource
associatedtype ImportSource
/**
Return `true` if an object should be created from `source`. Return `false` to ignore and skip `source`. The default implementation returns `true`.

View File

@@ -54,12 +54,12 @@ public protocol ImportableUniqueObject: ImportableObject {
/**
The data type for the import source. This is most commonly an `NSDictionary` or another external source such as an `NSUserDefaults`.
*/
typealias ImportSource
associatedtype ImportSource
/**
The data type for the entity's unique ID attribute
*/
typealias UniqueIDType: NSObject
associatedtype UniqueIDType: NSObject
/**
The keyPath to the entity's unique ID attribute

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.5.0</string>
<string>1.5.4</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>

View File

@@ -154,12 +154,13 @@ internal extension NSManagedObjectModel {
}
@nonobjc internal func entityTypesMapping() -> [String: NSManagedObject.Type] {
return self.entityNameMapping.reduce([:]) { (var mapping, pair) in
var mapping = [String: NSManagedObject.Type]()
self.entityNameMapping.forEach { (className, entityName) in
mapping[pair.1] = (NSClassFromString(pair.0)! as! NSManagedObject.Type)
return mapping
mapping[entityName] = (NSClassFromString(className)! as! NSManagedObject.Type)
}
return mapping
}
@nonobjc internal func mergedModels() -> [NSManagedObjectModel] {
@@ -249,15 +250,16 @@ internal extension NSManagedObjectModel {
return mapping as! [String: String]
}
let mapping = self.entities.reduce([String: String]()) {
(var mapping, entityDescription) -> [String: String] in
var mapping = [String: String]()
self.entities.forEach {
if let entityName = entityDescription.name {
guard let entityName = $0.name else {
let className = entityDescription.managedObjectClassName
mapping[className] = entityName
return
}
return mapping
let className = $0.managedObjectClassName
mapping[className] = entityName
}
setAssociatedCopiedObject(
mapping as NSDictionary,

View File

@@ -38,7 +38,7 @@ public extension CoreStore {
// MARK: Internal
internal static func log(level: LogLevel, message: String, fileName: StaticString = __FILE__, lineNumber: Int = __LINE__, functionName: StaticString = __FUNCTION__) {
internal static func log(level: LogLevel, message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
self.logger.log(
level: level,
@@ -49,7 +49,7 @@ public extension CoreStore {
)
}
internal static func handleError(error: NSError, _ message: String, fileName: StaticString = __FILE__, lineNumber: Int = __LINE__, functionName: StaticString = __FUNCTION__) {
internal static func handleError(error: NSError, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
self.logger.handleError(
error: error,
@@ -60,7 +60,7 @@ public extension CoreStore {
)
}
internal static func assert(@autoclosure condition: () -> Bool, _ message: String, fileName: StaticString = __FILE__, lineNumber: Int = __LINE__, functionName: StaticString = __FUNCTION__) {
internal static func assert(@autoclosure condition: () -> Bool, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
self.logger.assert(
condition,

View File

@@ -30,14 +30,14 @@ import CoreData
// MARK: - MigrationChain
/**
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.
A `MigrationChain` indicates the sequence of model versions to be used as the order for progressive migrations. 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 `[:]`) instructs the `DataStack` 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 progressive migrations:
```
let dataStack = DataStack(migrationChain: nil)
```
This means that the mapping model will be computed from the store's version straight to the `DataStack`'s model version.
To support incremental migrations, specify the linear order of versions:
To support progressive migrations, specify the linear order of versions:
```
let dataStack = DataStack(migrationChain:
["MyAppModel", "MyAppModelV2", "MyAppModelV3", "MyAppModelV4"])
@@ -111,22 +111,24 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
public init(dictionaryLiteral elements: (String, String)...) {
var valid = true
let versionTree = elements.reduce([String: String]()) { (var versionTree, tuple: (String, String)) -> [String: String] in
var versionTree = [String: String]()
elements.forEach { (sourceVersion, destinationVersion) in
if let _ = versionTree.updateValue(tuple.1, forKey: tuple.0) {
guard let _ = versionTree.updateValue(destinationVersion, forKey: sourceVersion) else {
CoreStore.assert(false, "\(typeName(MigrationChain))'s migration chain could not be created due to ambiguous version paths.")
valid = false
return
}
return versionTree
CoreStore.assert(false, "\(typeName(MigrationChain))'s migration chain could not be created due to ambiguous version paths.")
valid = false
}
let leafVersions = Set(
elements.filter { (tuple: (String, String)) -> Bool in
return versionTree[tuple.1] == nil
}.map { $1 }
}.map { $1 }
)
let isVersionAmbiguous = { (start: String) -> Bool in

View File

@@ -45,7 +45,7 @@ public protocol ListObserver: class {
/**
The `NSManagedObject` type for the observed list
*/
typealias ListEntityType: NSManagedObject
associatedtype ListEntityType: NSManagedObject
/**
Handles processing just before a change to the observed list occurs

View File

@@ -42,7 +42,7 @@ public protocol ObjectObserver: class {
/**
The `NSManagedObject` type for the observed object
*/
typealias ObjectEntityType: NSManagedObject
associatedtype ObjectEntityType: NSManagedObject
/**
Handles processing just before a change to the observed `object` occurs

View File

@@ -39,8 +39,10 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
/**
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` method was already called once.
- returns: a `SaveResult` containing the success or failure information
*/
public func commit() {
public func commitAndWait() -> SaveResult {
CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(),
@@ -52,7 +54,10 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
)
self.isCommitted = true
self.result = self.context.saveSynchronously()
let result = self.context.saveSynchronously()
self.result = result
return result
}
/**
@@ -197,6 +202,12 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
self.context.reset()
}
@available(*, deprecated=1.5.2, renamed="commitAndWait")
public func commit() {
self.commitAndWait()
}
// MARK: Internal

View File

@@ -55,6 +55,18 @@ public final class UnsafeDataTransaction: BaseDataTransaction {
}
}
/**
Saves the transaction changes and waits for completion synchronously. For a `UnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
- returns: a `SaveResult` containing the success or failure information
*/
public func commitAndWait() -> SaveResult {
let result = self.context.saveSynchronously()
self.result = result
return result
}
/**
Rolls back the transaction.
*/

View File

@@ -55,7 +55,7 @@ public final class DataStack {
- parameter modelName: the name of the (.xcdatamodeld) model file. If not specified, the application name will be used.
- parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used.
- parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for incremental migration. If not specified, will default to a non-migrating data stack.
- parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/
public required init(modelName: String = applicationName, bundle: NSBundle = NSBundle.mainBundle(), migrationChain: MigrationChain = nil) {

View File

@@ -37,7 +37,7 @@ private struct Static {
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
}
transaction.commit()
transaction.commitAndWait()
}
return dataStack

View File

@@ -61,7 +61,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
let palette = transaction.create(Into(Palette))
palette.setInitialValues()
transaction.commit()
transaction.commitAndWait()
}
let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue")))!

View File

@@ -39,7 +39,7 @@ class MigrationsDemoViewController: UIViewController {
let alert = UIAlertController(
title: "Migrations Demo",
message: "This demo shows how to run incremental migrations and how to support multiple model versions in a single project.\n\nThe persistent store contains 10000 organisms, which gain/lose properties when the migration evolves/devolves them.\n\nYou can use the \"mutate\" button to change an organism's properties then migrate to a different model to see how its value gets affected.",
message: "This demo shows how to run progressive migrations and how to support multiple model versions in a single project.\n\nThe persistent store contains 10000 organisms, which gain/lose properties when the migration evolves/devolves them.\n\nYou can use the \"mutate\" button to change an organism's properties then migrate to a different model to see how its value gets affected.",
preferredStyle: .Alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
@@ -267,7 +267,7 @@ class MigrationsDemoViewController: UIViewController {
self.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
self.titleLabel?.text = "Migrating: \(progress.localizedDescription)"
self.organismLabel?.text = "Incremental step \(progress.localizedAdditionalDescription)"
self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription)"
}
private func updateDisplay(reloadData reloadData: Bool, scrollToSelection: Bool, animated: Bool) {

View File

@@ -43,7 +43,7 @@ private struct Static {
account2.name = "Jane Doe HCD"
account2.friends = 314
transaction.commit()
transaction.commitAndWait()
}
return dataStack
@@ -77,7 +77,7 @@ private struct Static {
account2.name = "#janedoe_hcd"
account2.friends = 100
transaction.commit()
transaction.commitAndWait()
}
return dataStack

View File

@@ -32,7 +32,7 @@ private struct Static {
let place = transaction.create(Into(Place))
place.setInitialValues()
transaction.commit()
transaction.commitAndWait()
}
place = CoreStore.fetchOne(From(Place))
}
@@ -178,7 +178,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
let place = transaction.edit(Static.placeController.object)
place?.setInitialValues()
transaction.commit()
transaction.commitAndWait()
}
}

View File

@@ -265,7 +265,7 @@ class CoreStoreTests: XCTestCase {
)
XCTAssertTrue(numberOfDeletedObjects2 == 2, "numberOfDeletedObjects2 == 2 (actual: \(numberOfDeletedObjects2))")
transaction.commit()
transaction.commitAndWait()
}
CoreStore.beginSynchronous({ (transaction) -> Void in
@@ -277,7 +277,7 @@ class CoreStoreTests: XCTestCase {
obj.testEntityID = oldID
}
transaction.commit()
transaction.commitAndWait()
})
let objs1 = CoreStore.fetchAll(From(TestEntity1))
@@ -351,7 +351,7 @@ class CoreStoreTests: XCTestCase {
let obj5 = transaction.edit(obj5)
transaction.delete(obj5, obj6)
transaction.commit()
transaction.commitAndWait()
}
let count2 = CoreStore.queryValue(

30
Package.swift Normal file
View File

@@ -0,0 +1,30 @@
//
// Package.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import PackageDescription
let package = Package(
name: "CoreStore"
)

View File

@@ -1,12 +1,12 @@
# CoreStore
[![Build Status](https://img.shields.io/travis/JohnEstropia/CoreStore/develop.svg)](https://travis-ci.org/JohnEstropia/CoreStore)
[![Build Status](https://img.shields.io/travis/JohnEstropia/CoreStore/master.svg)](https://travis-ci.org/JohnEstropia/CoreStore)
[![Version](https://img.shields.io/cocoapods/v/CoreStore.svg?style=flat)](http://cocoadocs.org/docsets/CoreStore)
[![Platform](https://img.shields.io/cocoapods/p/CoreStore.svg?style=flat)](http://cocoadocs.org/docsets/CoreStore)
[![License](https://img.shields.io/cocoapods/l/CoreStore.svg?style=flat)](https://raw.githubusercontent.com/JohnEstropia/CoreStore/master/LICENSE)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
Unleashing the real power of Core Data with the elegance and safety of Swift
* Swift 2.1 (XCode 7.1), iOS 8+/OSX 10.10+ (or try out the [iOS 7 branch](https://github.com/JohnEstropia/CoreStore/tree/ios7_support_alpha))
* Swift 2.2 (Xcode 7.3), iOS 8+/OSX 10.10+ (or try out the [iOS 7 branch](https://github.com/JohnEstropia/CoreStore/tree/ios7_support_alpha))
[Click here for a wiki version of this README](https://github.com/JohnEstropia/CoreStore/wiki)
@@ -15,7 +15,7 @@ Unleashing the real power of Core Data with the elegance and safety of Swift
## 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.
- **Incremental Migrations!** Just tell the data stack the sequence of model versions and CoreStore will automatically use incremental migrations if needed on stores added to that stack.
- **Progressive Migrations!** Just tell the data stack the sequence of model versions and CoreStore will automatically use progressive migrations if needed on stores added to that stack.
- Ability to **plug-in your own logging framework**
- Gets around a limitation with other Core Data wrappers where the entity name should be the same as the `NSManagedObject` subclass name. CoreStore loads entity-to-class mappings from the managed object model file, so you are **free to name entities and their class names independently**.
- Provides type-safe, easy to configure **observers to replace `NSFetchedResultsController` and KVO**
@@ -36,7 +36,7 @@ Unleashing the real power of Core Data with the elegance and safety of Swift
- CoreStore Tutorials (All of these have demos in the **CoreStoreDemo** app project!)
- [Setting up](#setting-up)
- [Migrations](#migrations)
- [Incremental migrations](#incremental-migrations)
- [Progressive migrations](#progressive-migrations)
- [Forecasting migrations](#forecasting-migrations)
- [Saving and processing transactions](#saving-and-processing-transactions)
- [Transaction types](#transaction-types)
@@ -65,12 +65,15 @@ Unleashing the real power of Core Data with the elegance and safety of Swift
- [Installation](#installation)
- [Changesets](#changesets)
- [Upgrading from v0.2.0 to 1.0.0](#upgrading-from-v020-to-100)
- [Contact](#contact)
- [Who uses CoreStore?](#who-uses-corestore)
- [License](#license)
## TL;DR (a.k.a. sample codes)
Setting-up with incremental migration support:
Setting-up with progressive migration support:
```swift
CoreStore.defaultStack = DataStack(
modelName: "MyStore",
@@ -80,17 +83,12 @@ CoreStore.defaultStack = DataStack(
Adding a store:
```swift
do {
try CoreStore.addSQLiteStore(
fileName: "MyStore.sqlite",
completion: { (result) -> Void in
// ...
}
)
}
catch {
// ...
}
try CoreStore.addSQLiteStore(
fileName: "MyStore.sqlite",
completion: { (result) -> Void in
// ...
}
)
```
Starting transactions:
@@ -181,7 +179,7 @@ For most cases, this configuration is usable as it is. But for more hardcore set
```swift
let dataStack = DataStack(
modelName: "MyModel", // loads from the "MyModel.xcdatamodeld" file
migrationChain: ["MyStore", "MyStoreV2", "MyStoreV3"] // model versions for incremental migrations
migrationChain: ["MyStore", "MyStoreV2", "MyStoreV3"] // model versions for progressive migrations
)
do {
@@ -265,9 +263,9 @@ do {
completion: { (result) -> Void in
switch result {
case .Success(let persistentStore):
print("Successfully added sqlite store: \(persistentStore)"
print("Successfully added sqlite store: \(persistentStore)")
case .Failure(let error):
print("Failed adding sqlite store with error: \(error)"
print("Failed adding sqlite store with error: \(error)")
}
}
)
@@ -291,7 +289,7 @@ progress?.setProgressHandler { [weak self] (progress) -> Void in
This closure is executed on the main thread so UIKit calls can be done safely.
### Incremental migrations
### Progressive migrations
By default, CoreStore uses Core Data's default automatic migration mechanism. In other words, CoreStore will try to migrate the existing persistent store to the *.xcdatamodeld* file's current model version. If no mapping model is found from the store's version to the data model's version, CoreStore gives up and reports an error.
The `DataStack` lets you specify hints on how to break a migration into several sub-migrations using a `MigrationChain`. This is typically passed to the `DataStack` initializer and will be applied to all stores added to the `DataStack` with `addSQLiteStore(...)` and its variants:
@@ -314,7 +312,7 @@ This allows for different migration paths depending on the starting version. The
- MyAppModelV2-MyAppModelV4
- MyAppModelV3-MyAppModelV4
Initializing with empty values (either `nil`, `[]`, or `[:]`) instructs the `DataStack` to disable incremental migrations and revert to the default migration behavior (i.e. use the .xcdatamodel's current version as the final version):
Initializing with empty values (either `nil`, `[]`, or `[:]`) instructs the `DataStack` to disable progressive migrations and revert to the default migration behavior (i.e. use the .xcdatamodel's current version as the final version):
```swift
let dataStack = DataStack(migrationChain: nil)
```
@@ -1169,7 +1167,7 @@ let person2 = self.monitor[1, 2]
# Installation
- Requires:
- iOS 8 SDK and above
- Swift 2.0 (XCode 7 beta 6)
- Swift 2.1 (Xcode 7.2)
- Dependencies:
- [GCDKit](https://github.com/JohnEstropia/GCDKit)
@@ -1219,11 +1217,20 @@ The protocols above had their methods renamed as well, to retain the natural lan
- 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!
日本語で連絡していただいても構いません!
# Contact
Questions? Suggestions?
## License
Reach me on Twitter [@JohnEstropia](https://twitter.com/JohnEstropia)
or tag your Stackoverflow question with **corestore**
日本語の対応も可能なので是非!
# Who uses CoreStore?
Did CoreStore serve you well? I'd love to hear about your app :)
# License
CoreStore is released under an MIT license. See the LICENSE file for more information