mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-30 06:11:50 +02:00
optimize fetching objects with NSManagedObjectIDs
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = "CoreStore"
|
s.name = "CoreStore"
|
||||||
s.version = "1.2.1"
|
s.version = "1.3.0"
|
||||||
s.license = "MIT"
|
s.license = "MIT"
|
||||||
s.summary = "Simple, elegant, and smart Core Data programming with Swift"
|
s.summary = "Simple, elegant, and smart Core Data programming with Swift"
|
||||||
s.homepage = "https://github.com/JohnEstropia/CoreStore"
|
s.homepage = "https://github.com/JohnEstropia/CoreStore"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>FMWK</string>
|
<string>FMWK</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.2.1</string>
|
<string>1.3.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
|
|||||||
@@ -41,82 +41,8 @@ internal extension NSManagedObject {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal dynamic class func inContext(context: NSManagedObjectContext, withObjectID objectID: NSManagedObjectID) -> Self? {
|
|
||||||
|
|
||||||
return self.typedObjectInContext(context, objectID: objectID)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal func inContext(context: NSManagedObjectContext) -> Self? {
|
|
||||||
|
|
||||||
return self.typedObjectInContext(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal func deleteFromContext() {
|
internal func deleteFromContext() {
|
||||||
|
|
||||||
self.managedObjectContext?.deleteObject(self)
|
self.managedObjectContext?.deleteObject(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private class func typedObjectInContext<T: NSManagedObject>(context: NSManagedObjectContext, objectID: NSManagedObjectID) -> T? {
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let existingObject = try context.existingObjectWithID(objectID)
|
|
||||||
return (existingObject as! T)
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
|
|
||||||
CoreStore.handleError(
|
|
||||||
error as NSError,
|
|
||||||
"Failed to load existing \(typeName(self)) in context."
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func typedObjectInContext<T: NSManagedObject>(context: NSManagedObjectContext) -> T? {
|
|
||||||
|
|
||||||
let objectID = self.objectID
|
|
||||||
if objectID.temporaryID {
|
|
||||||
|
|
||||||
var objectIDError: NSError?
|
|
||||||
let didSucceed = withExtendedLifetime(self.managedObjectContext) { (context: NSManagedObjectContext?) -> Bool in
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
try context?.obtainPermanentIDsForObjects([self])
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
|
|
||||||
objectIDError = error as NSError
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if didSucceed != true {
|
|
||||||
|
|
||||||
CoreStore.handleError(
|
|
||||||
objectIDError ?? NSError(coreStoreErrorCode: .UnknownError),
|
|
||||||
"Failed to obtain permanent ID for object."
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
let existingObject = try context.existingObjectWithID(objectID)
|
|
||||||
return (existingObject as! T)
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
|
|
||||||
CoreStore.handleError(
|
|
||||||
error as NSError,
|
|
||||||
"Failed to load existing \(typeName(self)) in context."
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,51 @@ import CoreData
|
|||||||
|
|
||||||
internal extension NSManagedObjectContext {
|
internal extension NSManagedObjectContext {
|
||||||
|
|
||||||
// MARK: Public
|
// MARK: Internal
|
||||||
|
|
||||||
|
internal func fetchExisting<T: NSManagedObject>(object: T) -> T? {
|
||||||
|
|
||||||
|
if object.objectID.temporaryID {
|
||||||
|
|
||||||
|
var objectIDError: NSError?
|
||||||
|
let didSucceed = withExtendedLifetime(self) { (context: NSManagedObjectContext) -> Bool in
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
try context.obtainPermanentIDsForObjects([object])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
|
||||||
|
objectIDError = error as NSError
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if didSucceed != true {
|
||||||
|
|
||||||
|
CoreStore.handleError(
|
||||||
|
objectIDError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||||
|
"Failed to obtain permanent ID for object."
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
let existingObject = try self.existingObjectWithID(object.objectID)
|
||||||
|
return (existingObject as! T)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
|
||||||
|
CoreStore.handleError(
|
||||||
|
error as NSError,
|
||||||
|
"Failed to load existing \(typeName(object)) in context."
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
|
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
|
||||||
|
|
||||||
|
|||||||
@@ -195,7 +195,6 @@ public final class ObjectMonitor<T: NSManagedObject> {
|
|||||||
|
|
||||||
let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()
|
let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()
|
||||||
|
|
||||||
self.originalObjectID = originalObjectID
|
|
||||||
self.fetchedResultsController = fetchedResultsController
|
self.fetchedResultsController = fetchedResultsController
|
||||||
self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate
|
self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate
|
||||||
self.parentStack = dataStack
|
self.parentStack = dataStack
|
||||||
@@ -210,7 +209,6 @@ public final class ObjectMonitor<T: NSManagedObject> {
|
|||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private let originalObjectID: NSManagedObjectID
|
|
||||||
private let fetchedResultsController: NSFetchedResultsController
|
private let fetchedResultsController: NSFetchedResultsController
|
||||||
private let fetchedResultsControllerDelegate: FetchedResultsControllerDelegate
|
private let fetchedResultsControllerDelegate: FetchedResultsControllerDelegate
|
||||||
private var lastCommittedAttributes = [String: NSObject]()
|
private var lastCommittedAttributes = [String: NSObject]()
|
||||||
|
|||||||
@@ -110,8 +110,11 @@ public /*abstract*/ class BaseDataTransaction {
|
|||||||
self.bypassesQueueing || self.transactionQueue.isCurrentExecutionContext(),
|
self.bypassesQueueing || self.transactionQueue.isCurrentExecutionContext(),
|
||||||
"Attempted to update an entity of type \(typeName(object)) outside its designated queue."
|
"Attempted to update an entity of type \(typeName(object)) outside its designated queue."
|
||||||
)
|
)
|
||||||
|
guard let object = object else {
|
||||||
return object?.inContext(self.context)
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return self.context.fetchExisting(object)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,8 +135,7 @@ public /*abstract*/ class BaseDataTransaction {
|
|||||||
|| (into.configuration ?? Into.defaultConfigurationName) == objectID.persistentStore?.configurationName,
|
|| (into.configuration ?? Into.defaultConfigurationName) == objectID.persistentStore?.configurationName,
|
||||||
"Attempted to update an entity of type \(typeName(T)) but the specified persistent store do not match the `NSManagedObjectID`."
|
"Attempted to update an entity of type \(typeName(T)) but the specified persistent store do not match the `NSManagedObjectID`."
|
||||||
)
|
)
|
||||||
|
return self.fetchExisting(objectID) as? T
|
||||||
return (into.entityClass as! NSManagedObject.Type).inContext(self.context, withObjectID: objectID) as? T
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,8 +149,11 @@ public /*abstract*/ class BaseDataTransaction {
|
|||||||
self.bypassesQueueing || self.transactionQueue.isCurrentExecutionContext(),
|
self.bypassesQueueing || self.transactionQueue.isCurrentExecutionContext(),
|
||||||
"Attempted to delete an entity outside its designated queue."
|
"Attempted to delete an entity outside its designated queue."
|
||||||
)
|
)
|
||||||
|
guard let object = object else {
|
||||||
object?.inContext(self.context)?.deleteFromContext()
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.context.fetchExisting(object)?.deleteFromContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,9 +181,9 @@ public /*abstract*/ class BaseDataTransaction {
|
|||||||
)
|
)
|
||||||
|
|
||||||
let context = self.context
|
let context = self.context
|
||||||
for object in objects {
|
for case let object? in objects {
|
||||||
|
|
||||||
object?.inContext(context)?.deleteFromContext()
|
context.fetchExisting(object)?.deleteFromContext()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -159,13 +159,14 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
|||||||
|
|
||||||
if let mapView = self.mapView, let gesture = sender as? UILongPressGestureRecognizer where gesture.state == .Began {
|
if let mapView = self.mapView, let gesture = sender as? UILongPressGestureRecognizer where gesture.state == .Began {
|
||||||
|
|
||||||
|
let coordinate = mapView.convertPoint(
|
||||||
|
gesture.locationInView(mapView),
|
||||||
|
toCoordinateFromView: mapView
|
||||||
|
)
|
||||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||||
|
|
||||||
let place = transaction.edit(Static.placeController.object)
|
let place = transaction.edit(Static.placeController.object)
|
||||||
place?.coordinate = mapView.convertPoint(
|
place?.coordinate = coordinate
|
||||||
gesture.locationInView(mapView),
|
|
||||||
toCoordinateFromView: mapView
|
|
||||||
)
|
|
||||||
transaction.commit { (_) -> Void in }
|
transaction.commit { (_) -> Void in }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -956,7 +956,7 @@ let person2 = self.monitor[1, 2]
|
|||||||
# Installation
|
# Installation
|
||||||
- Requires:
|
- Requires:
|
||||||
- iOS 8 SDK and above
|
- iOS 8 SDK and above
|
||||||
- Swift 2.0 (XCode 7 beta 5)
|
- Swift 2.0 (XCode 7 beta 6)
|
||||||
- Dependencies:
|
- Dependencies:
|
||||||
- [GCDKit](https://github.com/JohnEstropia/GCDKit)
|
- [GCDKit](https://github.com/JohnEstropia/GCDKit)
|
||||||
|
|
||||||
@@ -968,7 +968,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
|
|||||||
|
|
||||||
### Install with Carthage
|
### Install with Carthage
|
||||||
```
|
```
|
||||||
github "JohnEstropia/CoreStore" >= 0.2.0
|
github "JohnEstropia/CoreStore" >= 1.3.0
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install as Git Submodule
|
### Install as Git Submodule
|
||||||
|
|||||||
Reference in New Issue
Block a user