optimize fetching objects with NSManagedObjectIDs

This commit is contained in:
John Rommel Estropia
2015-08-26 23:59:18 +09:00
parent 10e0cf8d2c
commit 16aabe1f3b
8 changed files with 67 additions and 93 deletions

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "1.2.1"
s.version = "1.3.0"
s.license = "MIT"
s.summary = "Simple, elegant, and smart Core Data programming with Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore"

View File

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

View File

@@ -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() {
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
}
}
}

View File

@@ -31,7 +31,51 @@ import CoreData
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? {

View File

@@ -195,7 +195,6 @@ public final class ObjectMonitor<T: NSManagedObject> {
let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()
self.originalObjectID = originalObjectID
self.fetchedResultsController = fetchedResultsController
self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate
self.parentStack = dataStack
@@ -210,7 +209,6 @@ public final class ObjectMonitor<T: NSManagedObject> {
// MARK: Private
private let originalObjectID: NSManagedObjectID
private let fetchedResultsController: NSFetchedResultsController
private let fetchedResultsControllerDelegate: FetchedResultsControllerDelegate
private var lastCommittedAttributes = [String: NSObject]()

View File

@@ -110,8 +110,11 @@ public /*abstract*/ class BaseDataTransaction {
self.bypassesQueueing || self.transactionQueue.isCurrentExecutionContext(),
"Attempted to update an entity of type \(typeName(object)) outside its designated queue."
)
return object?.inContext(self.context)
guard let object = object else {
return nil
}
return self.context.fetchExisting(object)
}
/**
@@ -132,8 +135,7 @@ public /*abstract*/ class BaseDataTransaction {
|| (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`."
)
return (into.entityClass as! NSManagedObject.Type).inContext(self.context, withObjectID: objectID) as? T
return self.fetchExisting(objectID) as? T
}
/**
@@ -147,8 +149,11 @@ public /*abstract*/ class BaseDataTransaction {
self.bypassesQueueing || self.transactionQueue.isCurrentExecutionContext(),
"Attempted to delete an entity outside its designated queue."
)
object?.inContext(self.context)?.deleteFromContext()
guard let object = object else {
return
}
self.context.fetchExisting(object)?.deleteFromContext()
}
/**
@@ -176,9 +181,9 @@ public /*abstract*/ class BaseDataTransaction {
)
let context = self.context
for object in objects {
for case let object? in objects {
object?.inContext(context)?.deleteFromContext()
context.fetchExisting(object)?.deleteFromContext()
}
}

View File

@@ -159,13 +159,14 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
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
let place = transaction.edit(Static.placeController.object)
place?.coordinate = mapView.convertPoint(
gesture.locationInView(mapView),
toCoordinateFromView: mapView
)
place?.coordinate = coordinate
transaction.commit { (_) -> Void in }
}
}

View File

@@ -956,7 +956,7 @@ let person2 = self.monitor[1, 2]
# Installation
- Requires:
- iOS 8 SDK and above
- Swift 2.0 (XCode 7 beta 5)
- Swift 2.0 (XCode 7 beta 6)
- Dependencies:
- [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
```
github "JohnEstropia/CoreStore" >= 0.2.0
github "JohnEstropia/CoreStore" >= 1.3.0
```
### Install as Git Submodule