mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-24 02:11:26 +01:00
Merge branch 'swift3_develop' into develop
# Conflicts: # .travis.yml # CoreStore.podspec # CoreStore.xcodeproj/project.pbxproj # Sources/Info.plist
This commit is contained in:
41
Sources/Internal/CoreStoreFetchRequest+CoreStore.swift
Normal file
41
Sources/Internal/CoreStoreFetchRequest+CoreStore.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// CoreStoreFetchRequest+CoreStore.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 Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
// MARK: - CoreStoreFetchRequest
|
||||
|
||||
internal extension CoreStoreFetchRequest {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
@nonobjc
|
||||
internal func dynamicCast<U: NSFetchRequestResult>() -> NSFetchRequest<U> {
|
||||
|
||||
return unsafeBitCast(self, to: NSFetchRequest<U>.self)
|
||||
}
|
||||
}
|
||||
@@ -31,12 +31,12 @@ import CoreData
|
||||
|
||||
// MARK: - CoreStoreFetchedResultsController
|
||||
|
||||
internal final class CoreStoreFetchedResultsController: NSFetchedResultsController {
|
||||
internal final class CoreStoreFetchedResultsController: NSFetchedResultsController<NSManagedObject> {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
@nonobjc
|
||||
internal convenience init<T: NSManagedObject>(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: (fetchRequest: NSFetchRequest) -> Void) {
|
||||
internal convenience init<T: NSManagedObject>(dataStack: DataStack, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
|
||||
|
||||
self.init(
|
||||
context: dataStack.mainContext,
|
||||
@@ -48,14 +48,14 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal init<T: NSManagedObject>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: (fetchRequest: NSFetchRequest) -> Void) {
|
||||
internal init<T: NSManagedObject>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
|
||||
|
||||
_ = from?.applyToFetchRequest(
|
||||
fetchRequest,
|
||||
context: context,
|
||||
applyAffectedStores: false
|
||||
)
|
||||
applyFetchClauses(fetchRequest: fetchRequest)
|
||||
applyFetchClauses(fetchRequest)
|
||||
|
||||
if let from = from {
|
||||
|
||||
@@ -68,7 +68,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
|
||||
|
||||
guard let from = (fetchRequest.entity.flatMap { $0.managedObjectClassName }).flatMap(NSClassFromString).flatMap(From.init) else {
|
||||
|
||||
CoreStore.abort("Attempted to create an \(cs_typeName(NSFetchedResultsController)) without a \(cs_typeName(From)) clause or an \(cs_typeName(NSEntityDescription)).")
|
||||
CoreStore.abort("Attempted to create a \(CoreStoreFetchedResultsController.self) without a \(cs_typeName(From<T>.self)) clause or an \(cs_typeName(NSEntityDescription.self)).")
|
||||
}
|
||||
|
||||
self.reapplyAffectedStores = { fetchRequest, context in
|
||||
@@ -88,16 +88,22 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
|
||||
@nonobjc
|
||||
internal func performFetchFromSpecifiedStores() throws {
|
||||
|
||||
if !self.reapplyAffectedStores(fetchRequest: self.fetchRequest, context: self.managedObjectContext) {
|
||||
if !self.reapplyAffectedStores(self.fetchRequest, self.managedObjectContext) {
|
||||
|
||||
CoreStore.log(
|
||||
.Warning,
|
||||
message: "Attempted to perform a fetch on an \(cs_typeName(NSFetchedResultsController)) but could not find any persistent store for the entity \(cs_typeName(self.fetchRequest.entityName))"
|
||||
.warning,
|
||||
message: "Attempted to perform a fetch on an \(cs_typeName(self)) but could not find any persistent store for the entity \(cs_typeName(self.fetchRequest.entityName))"
|
||||
)
|
||||
}
|
||||
try self.performFetch()
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func dynamicCast<U: NSFetchRequestResult>() -> NSFetchedResultsController<U> {
|
||||
|
||||
return unsafeBitCast(self, to: NSFetchedResultsController<U>.self)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
self.delegate = nil
|
||||
@@ -107,7 +113,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
|
||||
// MARK: Private
|
||||
|
||||
@nonobjc
|
||||
private let reapplyAffectedStores: (fetchRequest: NSFetchRequest, context: NSManagedObjectContext) -> Bool
|
||||
private let reapplyAffectedStores: (_ fetchRequest: NSFetchRequest<NSManagedObject>, _ context: NSManagedObjectContext) -> Bool
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
97
Sources/Internal/DispatchQueue+CoreStore.swift
Normal file
97
Sources/Internal/DispatchQueue+CoreStore.swift
Normal file
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// DispatchQueue+CoreStore.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 Foundation
|
||||
|
||||
|
||||
// MARK: - DispatchQueue
|
||||
|
||||
internal extension DispatchQueue {
|
||||
|
||||
@nonobjc
|
||||
internal static func serial(_ label: String, qos: DispatchQoS = .default) -> DispatchQueue {
|
||||
|
||||
return DispatchQueue(
|
||||
label: label,
|
||||
qos: qos,
|
||||
attributes: [],
|
||||
autoreleaseFrequency: .inherit,
|
||||
target: nil
|
||||
)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal static func concurrent(_ label: String, qos: DispatchQoS = .default) -> DispatchQueue {
|
||||
|
||||
return DispatchQueue(
|
||||
label: label,
|
||||
qos: qos,
|
||||
attributes: .concurrent,
|
||||
autoreleaseFrequency: .inherit,
|
||||
target: nil
|
||||
)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func cs_isCurrentExecutionContext() -> Bool {
|
||||
|
||||
let specific = ObjectIdentifier(self)
|
||||
|
||||
self.setSpecific(key: Static.specificKey, value: specific)
|
||||
return DispatchQueue.getSpecific(key: Static.specificKey) == specific
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func cs_sync<T>(_ closure: () throws -> T) rethrows -> T {
|
||||
|
||||
return try self.sync { try autoreleasepool(invoking: closure) }
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func cs_async(_ closure: @escaping () -> Void) {
|
||||
|
||||
self.async { autoreleasepool(invoking: closure) }
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func cs_barrierSync<T>(_ closure: () throws -> T) rethrows -> T {
|
||||
|
||||
return try self.sync(flags: .barrier) { try autoreleasepool(invoking: closure) }
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func cs_barrierAsync(_ closure: @escaping () -> Void) {
|
||||
|
||||
self.async(flags: .barrier) { autoreleasepool(invoking: closure) }
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private enum Static {
|
||||
|
||||
static let specificKey = DispatchSpecificKey<ObjectIdentifier>()
|
||||
}
|
||||
}
|
||||
@@ -33,21 +33,21 @@ import CoreData
|
||||
|
||||
internal protocol FetchedResultsControllerHandler: class {
|
||||
|
||||
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
|
||||
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeObject anObject: Any, atIndexPath indexPath: IndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
|
||||
|
||||
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
|
||||
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
|
||||
|
||||
func controllerWillChangeContent(controller: NSFetchedResultsController)
|
||||
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
|
||||
|
||||
func controllerDidChangeContent(controller: NSFetchedResultsController)
|
||||
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
|
||||
|
||||
func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String?
|
||||
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, sectionIndexTitleForSectionName sectionName: String?) -> String?
|
||||
}
|
||||
|
||||
|
||||
// MARK: - FetchedResultsControllerDelegate
|
||||
|
||||
internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResultsControllerDelegate {
|
||||
internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObject>: NSObject, NSFetchedResultsControllerDelegate {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
@@ -58,7 +58,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
internal weak var handler: FetchedResultsControllerHandler?
|
||||
|
||||
@nonobjc
|
||||
internal weak var fetchedResultsController: NSFetchedResultsController? {
|
||||
internal weak var fetchedResultsController: CoreStoreFetchedResultsController? {
|
||||
|
||||
didSet {
|
||||
|
||||
@@ -76,7 +76,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
// MARK: NSFetchedResultsControllerDelegate
|
||||
|
||||
@objc
|
||||
dynamic func controllerWillChangeContent(controller: NSFetchedResultsController) {
|
||||
dynamic func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||
|
||||
guard self.enabled else {
|
||||
|
||||
@@ -90,7 +90,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func controllerDidChangeContent(controller: NSFetchedResultsController) {
|
||||
dynamic func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||
|
||||
guard self.enabled else {
|
||||
|
||||
@@ -101,7 +101,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
|
||||
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
|
||||
|
||||
guard self.enabled else {
|
||||
|
||||
@@ -120,21 +120,32 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
// http://stackoverflow.com/questions/31383760/ios-9-attempt-to-delete-and-reload-the-same-index-path/31384014#31384014
|
||||
// https://forums.developer.apple.com/message/9998#9998
|
||||
// https://forums.developer.apple.com/message/31849#31849
|
||||
|
||||
if #available(iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
|
||||
|
||||
// I don't know if iOS 10 even attempted to fix this mess...
|
||||
if case .update = actualType,
|
||||
indexPath != nil,
|
||||
newIndexPath != nil {
|
||||
|
||||
actualType = .move
|
||||
}
|
||||
}
|
||||
|
||||
if #available(iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
|
||||
|
||||
// I don't know if iOS 10 even attempted to fix this mess...
|
||||
if case .Update = actualType
|
||||
where indexPath != nil && newIndexPath != nil {
|
||||
if case .update = actualType,
|
||||
indexPath != nil && newIndexPath != nil {
|
||||
|
||||
actualType = .Move
|
||||
actualType = .move
|
||||
}
|
||||
}
|
||||
|
||||
switch actualType {
|
||||
|
||||
case .Update:
|
||||
guard let section = indexPath?.indexAtPosition(0) else {
|
||||
case .update:
|
||||
guard let section = indexPath?[0] else {
|
||||
|
||||
return
|
||||
}
|
||||
@@ -144,7 +155,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
return
|
||||
}
|
||||
|
||||
case .Move:
|
||||
case .move:
|
||||
guard let indexPath = indexPath, let newIndexPath = newIndexPath else {
|
||||
|
||||
return
|
||||
@@ -153,25 +164,25 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
|
||||
break
|
||||
}
|
||||
if self.insertedSections.contains(indexPath.indexAtPosition(0)) {
|
||||
if self.insertedSections.contains(indexPath[0]) {
|
||||
|
||||
// Observers that handle the .Move change are advised to delete then reinsert the object instead of just moving. This is especially true when indexPath and newIndexPath are equal. For example, calling tableView.moveRowAtIndexPath(_:toIndexPath) when both indexPaths are the same will crash the tableView.
|
||||
self.handler?.controller(
|
||||
controller,
|
||||
didChangeObject: anObject,
|
||||
atIndexPath: indexPath,
|
||||
forChangeType: .Move,
|
||||
forChangeType: .move,
|
||||
newIndexPath: newIndexPath
|
||||
)
|
||||
return
|
||||
}
|
||||
if self.deletedSections.contains(indexPath.indexAtPosition(0)) {
|
||||
if self.deletedSections.contains(indexPath[0]) {
|
||||
|
||||
self.handler?.controller(
|
||||
controller,
|
||||
didChangeObject: anObject,
|
||||
atIndexPath: nil,
|
||||
forChangeType: .Insert,
|
||||
forChangeType: .insert,
|
||||
newIndexPath: indexPath
|
||||
)
|
||||
return
|
||||
@@ -180,7 +191,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
controller,
|
||||
didChangeObject: anObject,
|
||||
atIndexPath: indexPath,
|
||||
forChangeType: .Update,
|
||||
forChangeType: .update,
|
||||
newIndexPath: nil
|
||||
)
|
||||
return
|
||||
@@ -199,7 +210,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
|
||||
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
|
||||
|
||||
guard self.enabled else {
|
||||
|
||||
@@ -208,8 +219,8 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
|
||||
switch type {
|
||||
|
||||
case .Delete: self.deletedSections.insert(sectionIndex)
|
||||
case .Insert: self.insertedSections.insert(sectionIndex)
|
||||
case .delete: self.deletedSections.insert(sectionIndex)
|
||||
case .insert: self.insertedSections.insert(sectionIndex)
|
||||
default: break
|
||||
}
|
||||
|
||||
@@ -222,7 +233,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String) -> String? {
|
||||
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, sectionIndexTitleForSectionName sectionName: String) -> String? {
|
||||
|
||||
return self.handler?.controller(
|
||||
controller,
|
||||
|
||||
@@ -25,70 +25,9 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: Associated Objects
|
||||
|
||||
// MARK: - Custom AutoreleasePool
|
||||
|
||||
internal func cs_autoreleasepool(@noescape closure: () -> Void) {
|
||||
|
||||
autoreleasepool(closure)
|
||||
}
|
||||
|
||||
internal func cs_autoreleasepool<T>(@noescape closure: () -> T) -> T {
|
||||
|
||||
var closureValue: T!
|
||||
autoreleasepool {
|
||||
|
||||
closureValue = closure()
|
||||
}
|
||||
|
||||
return closureValue
|
||||
}
|
||||
|
||||
internal func cs_autoreleasepool<T>(@noescape closure: () throws -> T) throws -> T {
|
||||
|
||||
var closureValue: T!
|
||||
var closureError: ErrorType?
|
||||
autoreleasepool {
|
||||
|
||||
do {
|
||||
|
||||
closureValue = try closure()
|
||||
}
|
||||
catch {
|
||||
|
||||
closureError = error
|
||||
}
|
||||
}
|
||||
|
||||
if let closureError = closureError {
|
||||
|
||||
throw closureError
|
||||
}
|
||||
return closureValue
|
||||
}
|
||||
|
||||
internal func cs_autoreleasepool(@noescape closure: () throws -> Void) throws {
|
||||
|
||||
var closureError: ErrorType?
|
||||
autoreleasepool {
|
||||
|
||||
do {
|
||||
|
||||
try closure()
|
||||
}
|
||||
catch {
|
||||
|
||||
closureError = error
|
||||
}
|
||||
}
|
||||
|
||||
if let closureError = closureError {
|
||||
|
||||
throw closureError
|
||||
}
|
||||
}
|
||||
|
||||
internal func cs_getAssociatedObjectForKey<T: AnyObject>(key: UnsafePointer<Void>, inObject object: AnyObject) -> T? {
|
||||
internal func cs_getAssociatedObjectForKey<T: AnyObject>(_ key: UnsafeRawPointer, inObject object: Any) -> T? {
|
||||
|
||||
switch objc_getAssociatedObject(object, key) {
|
||||
|
||||
@@ -103,17 +42,17 @@ internal func cs_getAssociatedObjectForKey<T: AnyObject>(key: UnsafePointer<Void
|
||||
}
|
||||
}
|
||||
|
||||
internal func cs_setAssociatedRetainedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
|
||||
internal func cs_setAssociatedRetainedObject<T: AnyObject>(_ associatedObject: T?, forKey key: UnsafeRawPointer, inObject object: Any) {
|
||||
|
||||
objc_setAssociatedObject(object, key, associatedObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
|
||||
internal func cs_setAssociatedCopiedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
|
||||
internal func cs_setAssociatedCopiedObject<T: AnyObject>(_ associatedObject: T?, forKey key: UnsafeRawPointer, inObject object: Any) {
|
||||
|
||||
objc_setAssociatedObject(object, key, associatedObject, .OBJC_ASSOCIATION_COPY_NONATOMIC)
|
||||
}
|
||||
|
||||
internal func cs_setAssociatedWeakObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
|
||||
internal func cs_setAssociatedWeakObject<T: AnyObject>(_ associatedObject: T?, forKey key: UnsafeRawPointer, inObject object: Any) {
|
||||
|
||||
if let associatedObject = associatedObject {
|
||||
|
||||
@@ -128,22 +67,27 @@ internal func cs_setAssociatedWeakObject<T: AnyObject>(associatedObject: T?, for
|
||||
|
||||
// MARK: Printing Utilities
|
||||
|
||||
internal func cs_typeName<T>(value: T) -> String {
|
||||
internal func cs_typeName<T>(_ value: T) -> String {
|
||||
|
||||
return "'\(String(reflecting: value.dynamicType))'"
|
||||
return "'\(String(reflecting: type(of: value)))'"
|
||||
}
|
||||
|
||||
internal func cs_typeName<T>(value: T.Type) -> String {
|
||||
internal func cs_typeName<T>(_ value: T.Type) -> String {
|
||||
|
||||
return "'\(value)'"
|
||||
}
|
||||
|
||||
internal func cs_typeName(value: AnyClass) -> String {
|
||||
internal func cs_typeName(_ value: AnyClass) -> String {
|
||||
|
||||
return "'\(value)'"
|
||||
}
|
||||
|
||||
internal func cs_typeName(name: String?) -> String {
|
||||
internal func cs_typeName(_ name: String) -> String {
|
||||
|
||||
return "<\(name)>"
|
||||
}
|
||||
|
||||
internal func cs_typeName(_ name: String?) -> String {
|
||||
|
||||
return "<\(name ?? "unknown")>"
|
||||
}
|
||||
|
||||
@@ -29,15 +29,15 @@ import CoreData
|
||||
|
||||
// MARK: - MigrationManager
|
||||
|
||||
internal final class MigrationManager: NSMigrationManager, NSProgressReporting {
|
||||
internal final class MigrationManager: NSMigrationManager, ProgressReporting {
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
override func didChangeValueForKey(key: String) {
|
||||
override func didChangeValue(forKey key: String) {
|
||||
|
||||
super.didChangeValueForKey(key)
|
||||
super.didChangeValue(forKey: key)
|
||||
|
||||
guard key == "migrationProgress" else {
|
||||
guard key == #keyPath(NSMigrationManager.migrationProgress) else {
|
||||
|
||||
return
|
||||
}
|
||||
@@ -48,7 +48,7 @@ internal final class MigrationManager: NSMigrationManager, NSProgressReporting {
|
||||
|
||||
// MARK: NSMigrationManager
|
||||
|
||||
init(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, progress: NSProgress) {
|
||||
init(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, progress: Progress) {
|
||||
|
||||
self.progress = progress
|
||||
|
||||
@@ -56,7 +56,7 @@ internal final class MigrationManager: NSMigrationManager, NSProgressReporting {
|
||||
}
|
||||
|
||||
|
||||
// MARK: NSProgressReporting
|
||||
// MARK: ProgressReporting
|
||||
|
||||
let progress: NSProgress
|
||||
let progress: Progress
|
||||
}
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
#if USE_FRAMEWORKS
|
||||
import GCDKit
|
||||
#endif
|
||||
|
||||
|
||||
// MARK: - NSManagedObjectContext
|
||||
@@ -50,7 +47,7 @@ internal extension NSManagedObjectContext {
|
||||
set {
|
||||
|
||||
cs_setAssociatedCopiedObject(
|
||||
NSNumber(bool: newValue),
|
||||
NSNumber(value: newValue),
|
||||
forKey: &PropertyKeys.shouldCascadeSavesToParent,
|
||||
inObject: self
|
||||
)
|
||||
@@ -58,40 +55,30 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func entityDescriptionForEntityType(entity: NSManagedObject.Type) -> NSEntityDescription? {
|
||||
internal func entityDescriptionForEntityType(_ entity: NSManagedObject.Type) -> NSEntityDescription? {
|
||||
|
||||
return self.entityDescriptionForEntityClass(entity)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func entityDescriptionForEntityClass(entity: AnyClass) -> NSEntityDescription? {
|
||||
internal func entityDescriptionForEntityClass(_ entity: AnyClass) -> NSEntityDescription? {
|
||||
|
||||
guard let entityName = self.parentStack?.entityNameForEntityClass(entity) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return NSEntityDescription.entityForName(
|
||||
entityName,
|
||||
inManagedObjectContext: self
|
||||
return NSEntityDescription.entity(
|
||||
forEntityName: entityName,
|
||||
in: self
|
||||
)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func setupForCoreStoreWithContextName(contextName: String) {
|
||||
|
||||
#if USE_FRAMEWORKS
|
||||
|
||||
self.name = contextName
|
||||
#else
|
||||
|
||||
if #available(iOS 8.0, *) {
|
||||
|
||||
self.name = contextName
|
||||
}
|
||||
#endif
|
||||
internal func setupForCoreStoreWithContextName(_ contextName: String) {
|
||||
|
||||
self.name = contextName
|
||||
self.observerForWillSaveNotification = NotificationObserver(
|
||||
notificationName: NSManagedObjectContextWillSaveNotification,
|
||||
notificationName: NSNotification.Name.NSManagedObjectContextWillSave,
|
||||
object: self,
|
||||
closure: { (note) -> Void in
|
||||
|
||||
@@ -105,7 +92,7 @@ internal extension NSManagedObjectContext {
|
||||
|
||||
do {
|
||||
|
||||
try context.obtainPermanentIDsForObjects(Array(insertedObjects))
|
||||
try context.obtainPermanentIDs(for: Array(insertedObjects))
|
||||
}
|
||||
catch {
|
||||
|
||||
|
||||
@@ -29,20 +29,20 @@ import CoreData
|
||||
|
||||
// MARK: - NSManagedObjectContext
|
||||
|
||||
internal extension NSManagedObjectContext {
|
||||
extension NSManagedObjectContext: FetchableSource, QueryableSource {
|
||||
|
||||
// MARK: Internal: Fetch Existing
|
||||
// MARK: FetchableSource
|
||||
|
||||
@nonobjc
|
||||
internal func fetchExisting<T: NSManagedObject>(object: T) -> T? {
|
||||
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
|
||||
|
||||
if object.objectID.temporaryID {
|
||||
if object.objectID.isTemporaryID {
|
||||
|
||||
do {
|
||||
|
||||
try withExtendedLifetime(self) { (context: NSManagedObjectContext) -> Void in
|
||||
|
||||
try context.obtainPermanentIDsForObjects([object])
|
||||
try context.obtainPermanentIDs(for: [object])
|
||||
}
|
||||
}
|
||||
catch {
|
||||
@@ -54,10 +54,9 @@ internal extension NSManagedObjectContext {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
let existingObject = try self.existingObjectWithID(object.objectID)
|
||||
let existingObject = try self.existingObject(with: object.objectID)
|
||||
return (existingObject as! T)
|
||||
}
|
||||
catch {
|
||||
@@ -70,125 +69,86 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal: Fetch One
|
||||
@nonobjc
|
||||
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
|
||||
|
||||
do {
|
||||
|
||||
return (try self.existingObject(with: objectID) as! T)
|
||||
}
|
||||
catch _ {
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
|
||||
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
|
||||
|
||||
return objects.flatMap { (try? self.existingObject(with: $0.objectID)) as? T }
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
|
||||
|
||||
return objectIDs.flatMap { (try? self.existingObject(with: $0)) as? T }
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
|
||||
|
||||
|
||||
return self.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
|
||||
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
|
||||
|
||||
let fetchRequest = CoreStoreFetchRequest()
|
||||
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 1
|
||||
fetchRequest.resultType = .ManagedObjectResultType
|
||||
fetchRequest.resultType = .managedObjectResultType
|
||||
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
|
||||
|
||||
guard storeFound else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.fetchOne(fetchRequest)
|
||||
return self.fetchOne(fetchRequest.dynamicCast())
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchOne<T: NSManagedObject>(fetchRequest: NSFetchRequest) -> T? {
|
||||
|
||||
var fetchResults: [T]?
|
||||
var fetchError: ErrorType?
|
||||
self.performBlockAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.executeFetchRequest(fetchRequest) as? [T]
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults?.first
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal: Fetch All
|
||||
|
||||
@nonobjc
|
||||
internal func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
|
||||
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
|
||||
|
||||
return self.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
|
||||
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
|
||||
|
||||
let fetchRequest = CoreStoreFetchRequest()
|
||||
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .ManagedObjectResultType
|
||||
fetchRequest.resultType = .managedObjectResultType
|
||||
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
|
||||
|
||||
guard storeFound else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.fetchAll(fetchRequest)
|
||||
return self.fetchAll(fetchRequest.dynamicCast())
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchAll<T: NSManagedObject>(fetchRequest: NSFetchRequest) -> [T]? {
|
||||
|
||||
var fetchResults: [T]?
|
||||
var fetchError: ErrorType?
|
||||
self.performBlockAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.executeFetchRequest(fetchRequest) as? [T]
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal: Count
|
||||
|
||||
@nonobjc
|
||||
internal func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
|
||||
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
|
||||
|
||||
return self.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
|
||||
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
|
||||
|
||||
let fetchRequest = CoreStoreFetchRequest()
|
||||
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
|
||||
@@ -198,127 +158,65 @@ internal extension NSManagedObjectContext {
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.fetchCount(fetchRequest)
|
||||
return self.fetchCount(fetchRequest.dynamicCast())
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchCount(fetchRequest: NSFetchRequest) -> Int? {
|
||||
|
||||
var count = 0
|
||||
var countError: ErrorType?
|
||||
self.performBlockAndWait {
|
||||
|
||||
do {
|
||||
|
||||
count = try self.countForFetchRequest(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
countError = error
|
||||
}
|
||||
}
|
||||
if count == NSNotFound {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(countError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal: Object ID
|
||||
|
||||
@nonobjc
|
||||
internal func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
|
||||
return self.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
let fetchRequest = CoreStoreFetchRequest()
|
||||
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 1
|
||||
fetchRequest.resultType = .ManagedObjectIDResultType
|
||||
fetchRequest.resultType = .managedObjectIDResultType
|
||||
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
|
||||
|
||||
guard storeFound else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.fetchObjectID(fetchRequest)
|
||||
return self.fetchObjectID(fetchRequest.dynamicCast())
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchObjectID(fetchRequest: NSFetchRequest) -> NSManagedObjectID? {
|
||||
|
||||
var fetchResults: [NSManagedObjectID]?
|
||||
var fetchError: ErrorType?
|
||||
self.performBlockAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.executeFetchRequest(fetchRequest) as? [NSManagedObjectID]
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults?.first
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal: Object IDs
|
||||
|
||||
@nonobjc
|
||||
internal func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
|
||||
return self.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
let fetchRequest = CoreStoreFetchRequest()
|
||||
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .ManagedObjectIDResultType
|
||||
fetchRequest.resultType = .managedObjectIDResultType
|
||||
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
|
||||
|
||||
guard storeFound else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.fetchObjectIDs(fetchRequest)
|
||||
return self.fetchObjectIDs(fetchRequest.dynamicCast())
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchObjectIDs(fetchRequest: NSFetchRequest) -> [NSManagedObjectID]? {
|
||||
internal func fetchObjectIDs(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) -> [NSManagedObjectID]? {
|
||||
|
||||
var fetchResults: [NSManagedObjectID]?
|
||||
var fetchError: ErrorType?
|
||||
self.performBlockAndWait {
|
||||
var fetchError: Error?
|
||||
self.performAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.executeFetchRequest(fetchRequest) as? [NSManagedObjectID]
|
||||
fetchResults = try self.fetch(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
@@ -333,85 +231,20 @@ internal extension NSManagedObjectContext {
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal: Delete All
|
||||
// MARK: QueryableSource
|
||||
|
||||
@nonobjc
|
||||
internal func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
|
||||
|
||||
return self.deleteAll(from, deleteClauses)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
|
||||
|
||||
let fetchRequest = CoreStoreFetchRequest()
|
||||
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .ManagedObjectResultType
|
||||
fetchRequest.returnsObjectsAsFaults = true
|
||||
fetchRequest.includesPropertyValues = false
|
||||
deleteClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
|
||||
|
||||
guard storeFound else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.deleteAll(fetchRequest)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func deleteAll(fetchRequest: NSFetchRequest) -> Int? {
|
||||
|
||||
var numberOfDeletedObjects: Int?
|
||||
var fetchError: ErrorType?
|
||||
self.performBlockAndWait {
|
||||
|
||||
cs_autoreleasepool {
|
||||
|
||||
do {
|
||||
|
||||
let fetchResults = try self.executeFetchRequest(fetchRequest) as? [NSManagedObject] ?? []
|
||||
for object in fetchResults {
|
||||
|
||||
self.deleteObject(object)
|
||||
}
|
||||
numberOfDeletedObjects = fetchResults.count
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
}
|
||||
if numberOfDeletedObjects == nil {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
return numberOfDeletedObjects
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal: Value
|
||||
|
||||
@nonobjc
|
||||
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
|
||||
|
||||
return self.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
|
||||
|
||||
let fetchRequest = CoreStoreFetchRequest()
|
||||
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
|
||||
@@ -430,82 +263,13 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func queryValue<U: SelectValueResultType>(selectTerms: [SelectTerm], fetchRequest: NSFetchRequest) -> U? {
|
||||
|
||||
var fetchResults: [AnyObject]?
|
||||
var fetchError: ErrorType?
|
||||
self.performBlockAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.executeFetchRequest(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if let fetchResults = fetchResults {
|
||||
|
||||
if let rawResult = fetchResults.first as? NSDictionary,
|
||||
let rawObject: AnyObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] {
|
||||
|
||||
return Select<U>.ReturnType.fromResultObject(rawObject)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func queryValue(selectTerms: [SelectTerm], fetchRequest: NSFetchRequest) -> AnyObject? {
|
||||
|
||||
var fetchResults: [AnyObject]?
|
||||
var fetchError: ErrorType?
|
||||
self.performBlockAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.executeFetchRequest(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if let fetchResults = fetchResults {
|
||||
|
||||
if let rawResult = fetchResults.first as? NSDictionary,
|
||||
let rawObject: AnyObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] {
|
||||
|
||||
return rawObject
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal: Attributes
|
||||
|
||||
@nonobjc
|
||||
internal func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
|
||||
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
|
||||
|
||||
return self.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
|
||||
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
|
||||
|
||||
let fetchRequest = CoreStoreFetchRequest()
|
||||
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
|
||||
@@ -522,16 +286,210 @@ internal extension NSManagedObjectContext {
|
||||
return self.queryAttributes(fetchRequest)
|
||||
}
|
||||
|
||||
|
||||
// MARK: FetchableSource, QueryableSource
|
||||
|
||||
@nonobjc
|
||||
internal func queryAttributes(fetchRequest: NSFetchRequest) -> [[NSString: AnyObject]]? {
|
||||
public func internalContext() -> NSManagedObjectContext {
|
||||
|
||||
var fetchResults: [AnyObject]?
|
||||
var fetchError: ErrorType?
|
||||
self.performBlockAndWait {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSManagedObjectContext (Internal)
|
||||
|
||||
internal extension NSManagedObjectContext {
|
||||
|
||||
// MARK: Fetching
|
||||
|
||||
@nonobjc
|
||||
internal func fetchOne<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> T? {
|
||||
|
||||
var fetchResults: [T]?
|
||||
var fetchError: Error?
|
||||
self.performAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.executeFetchRequest(fetchRequest)
|
||||
fetchResults = try self.fetch(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return fetchResults?.first
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> [T]? {
|
||||
|
||||
var fetchResults: [T]?
|
||||
var fetchError: Error?
|
||||
self.performAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.fetch(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return fetchResults
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchCount(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Int? {
|
||||
|
||||
var count = 0
|
||||
var countError: Error?
|
||||
self.performAndWait {
|
||||
|
||||
do {
|
||||
|
||||
count = try self.count(for: fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
countError = error
|
||||
}
|
||||
}
|
||||
if count == NSNotFound {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(countError),
|
||||
"Failed executing count request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func fetchObjectID(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) -> NSManagedObjectID? {
|
||||
|
||||
var fetchResults: [NSManagedObjectID]?
|
||||
var fetchError: Error?
|
||||
self.performAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.fetch(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return fetchResults?.first
|
||||
}
|
||||
|
||||
|
||||
// MARK: Querying
|
||||
|
||||
@nonobjc
|
||||
internal func queryValue<U: SelectValueResultType>(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> U? {
|
||||
|
||||
var fetchResults: [Any]?
|
||||
var fetchError: Error?
|
||||
self.performAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.fetch(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if let fetchResults = fetchResults {
|
||||
|
||||
if let rawResult = fetchResults.first as? NSDictionary,
|
||||
let rawObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] {
|
||||
|
||||
return Select<U>.ReturnType.fromResultObject(rawObject)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func queryValue(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Any? {
|
||||
|
||||
var fetchResults: [Any]?
|
||||
var fetchError: Error?
|
||||
self.performAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.fetch(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
if let fetchResults = fetchResults {
|
||||
|
||||
if let rawResult = fetchResults.first as? NSDictionary,
|
||||
let rawObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] {
|
||||
|
||||
return rawObject
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func queryAttributes(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> [[String: Any]]? {
|
||||
|
||||
var fetchResults: [Any]?
|
||||
var fetchError: Error?
|
||||
self.performAndWait {
|
||||
|
||||
do {
|
||||
|
||||
fetchResults = try self.fetch(fetchRequest)
|
||||
}
|
||||
catch {
|
||||
|
||||
@@ -549,4 +507,67 @@ internal extension NSManagedObjectContext {
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// MARK: Deleting
|
||||
|
||||
@nonobjc
|
||||
internal func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
|
||||
|
||||
return self.deleteAll(from, deleteClauses)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
|
||||
|
||||
let fetchRequest = CoreStoreFetchRequest()
|
||||
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
|
||||
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .managedObjectResultType
|
||||
fetchRequest.returnsObjectsAsFaults = true
|
||||
fetchRequest.includesPropertyValues = false
|
||||
deleteClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
|
||||
|
||||
guard storeFound else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.deleteAll(fetchRequest.dynamicCast())
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func deleteAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> Int? {
|
||||
|
||||
var numberOfDeletedObjects: Int?
|
||||
var fetchError: Error?
|
||||
self.performAndWait {
|
||||
|
||||
autoreleasepool {
|
||||
|
||||
do {
|
||||
|
||||
let fetchResults = try self.fetch(fetchRequest)
|
||||
for object in fetchResults {
|
||||
|
||||
self.delete(object)
|
||||
}
|
||||
numberOfDeletedObjects = fetchResults.count
|
||||
}
|
||||
catch {
|
||||
|
||||
fetchError = error
|
||||
}
|
||||
}
|
||||
}
|
||||
if numberOfDeletedObjects == nil {
|
||||
|
||||
CoreStore.log(
|
||||
CoreStoreError(fetchError),
|
||||
"Failed executing fetch request."
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return numberOfDeletedObjects
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ internal extension NSManagedObjectContext {
|
||||
|
||||
get {
|
||||
|
||||
if let parentContext = self.parentContext {
|
||||
if let parentContext = self.parent {
|
||||
|
||||
return parentContext.parentStack
|
||||
}
|
||||
@@ -47,7 +47,7 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
set {
|
||||
|
||||
guard self.parentContext == nil else {
|
||||
guard self.parent == nil else {
|
||||
|
||||
return
|
||||
}
|
||||
@@ -61,9 +61,9 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal static func rootSavingContextForCoordinator(coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
|
||||
internal static func rootSavingContextForCoordinator(_ coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
|
||||
|
||||
let context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
|
||||
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
||||
context.persistentStoreCoordinator = coordinator
|
||||
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
||||
context.undoManager = nil
|
||||
@@ -72,18 +72,20 @@ internal extension NSManagedObjectContext {
|
||||
#if os(iOS) || os(OSX)
|
||||
|
||||
context.observerForDidImportUbiquitousContentChangesNotification = NotificationObserver(
|
||||
notificationName: NSPersistentStoreDidImportUbiquitousContentChangesNotification,
|
||||
notificationName: NSNotification.Name.NSPersistentStoreDidImportUbiquitousContentChanges,
|
||||
object: coordinator,
|
||||
closure: { [weak context] (note) -> Void in
|
||||
|
||||
context?.performBlock { () -> Void in
|
||||
context?.perform { () -> Void in
|
||||
|
||||
let updatedObjectIDs = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObjectID>) ?? []
|
||||
for objectID in updatedObjectIDs {
|
||||
if let updatedObjectIDs = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObjectID>) {
|
||||
|
||||
context?.objectWithID(objectID).willAccessValueForKey(nil)
|
||||
for objectID in updatedObjectIDs {
|
||||
|
||||
context?.object(with: objectID).willAccessValue(forKey: nil)
|
||||
}
|
||||
}
|
||||
context?.mergeChangesFromContextDidSaveNotification(note)
|
||||
context?.mergeChanges(fromContextDidSave: note)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -94,15 +96,15 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal static func mainContextForRootContext(rootContext: NSManagedObjectContext) -> NSManagedObjectContext {
|
||||
internal static func mainContextForRootContext(_ rootContext: NSManagedObjectContext) -> NSManagedObjectContext {
|
||||
|
||||
let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
|
||||
context.parentContext = rootContext
|
||||
let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
|
||||
context.parent = rootContext
|
||||
context.mergePolicy = NSRollbackMergePolicy
|
||||
context.undoManager = nil
|
||||
context.setupForCoreStoreWithContextName("com.corestore.maincontext")
|
||||
context.observerForDidSaveNotification = NotificationObserver(
|
||||
notificationName: NSManagedObjectContextDidSaveNotification,
|
||||
notificationName: NSNotification.Name.NSManagedObjectContextDidSave,
|
||||
object: rootContext,
|
||||
closure: { [weak context] (note) -> Void in
|
||||
|
||||
@@ -113,21 +115,22 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
let mergeChanges = { () -> Void in
|
||||
|
||||
let updatedObjects = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject>) ?? []
|
||||
for object in updatedObjects {
|
||||
if let updatedObjects = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject>) {
|
||||
|
||||
context.objectWithID(object.objectID).willAccessValueForKey(nil)
|
||||
for object in updatedObjects {
|
||||
|
||||
context.object(with: object.objectID).willAccessValue(forKey: nil)
|
||||
}
|
||||
}
|
||||
context.mergeChangesFromContextDidSaveNotification(note)
|
||||
context.mergeChanges(fromContextDidSave: note)
|
||||
}
|
||||
|
||||
if rootContext.isSavingSynchronously == true {
|
||||
|
||||
context.performBlockAndWait(mergeChanges)
|
||||
context.performAndWait(mergeChanges)
|
||||
}
|
||||
else {
|
||||
|
||||
context.performBlock(mergeChanges)
|
||||
context.perform(mergeChanges)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
#if USE_FRAMEWORKS
|
||||
import GCDKit
|
||||
#endif
|
||||
|
||||
|
||||
// MARK: - NSManagedObjectContext
|
||||
@@ -70,13 +67,55 @@ internal extension NSManagedObjectContext {
|
||||
set {
|
||||
|
||||
cs_setAssociatedWeakObject(
|
||||
newValue.flatMap { NSNumber(bool: $0) },
|
||||
newValue.flatMap { NSNumber(value: $0) },
|
||||
forKey: &PropertyKeys.isSavingSynchronously,
|
||||
inObject: self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal var isTransactionContext: Bool {
|
||||
|
||||
get {
|
||||
|
||||
let value: NSNumber? = cs_getAssociatedObjectForKey(
|
||||
&PropertyKeys.isTransactionContext,
|
||||
inObject: self
|
||||
)
|
||||
return value?.boolValue == true
|
||||
}
|
||||
set {
|
||||
|
||||
cs_setAssociatedCopiedObject(
|
||||
NSNumber(value: newValue),
|
||||
forKey: &PropertyKeys.isTransactionContext,
|
||||
inObject: self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal var isDataStackContext: Bool {
|
||||
|
||||
get {
|
||||
|
||||
let value: NSNumber? = cs_getAssociatedObjectForKey(
|
||||
&PropertyKeys.isDataStackContext,
|
||||
inObject: self
|
||||
)
|
||||
return value?.boolValue == true
|
||||
}
|
||||
set {
|
||||
|
||||
cs_setAssociatedCopiedObject(
|
||||
NSNumber(value: newValue),
|
||||
forKey: &PropertyKeys.isDataStackContext,
|
||||
inObject: self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func isRunningInAllowedQueue() -> Bool {
|
||||
|
||||
@@ -88,10 +127,10 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func temporaryContextInTransactionWithConcurrencyType(concurrencyType: NSManagedObjectContextConcurrencyType) -> NSManagedObjectContext {
|
||||
internal func temporaryContextInTransactionWithConcurrencyType(_ concurrencyType: NSManagedObjectContextConcurrencyType) -> NSManagedObjectContext {
|
||||
|
||||
let context = NSManagedObjectContext(concurrencyType: concurrencyType)
|
||||
context.parentContext = self
|
||||
context.parent = self
|
||||
context.parentStack = self.parentStack
|
||||
context.setupForCoreStoreWithContextName("com.corestore.temporarycontext")
|
||||
context.shouldCascadeSavesToParent = (self.parentStack?.rootSavingContext == self)
|
||||
@@ -105,7 +144,7 @@ internal extension NSManagedObjectContext {
|
||||
|
||||
var result = SaveResult(hasChanges: false)
|
||||
|
||||
self.performBlockAndWait {
|
||||
self.performAndWait {
|
||||
|
||||
guard self.hasChanges else {
|
||||
|
||||
@@ -123,20 +162,20 @@ internal extension NSManagedObjectContext {
|
||||
let saveError = CoreStoreError(error)
|
||||
CoreStore.log(
|
||||
saveError,
|
||||
"Failed to save \(cs_typeName(NSManagedObjectContext))."
|
||||
"Failed to save \(cs_typeName(NSManagedObjectContext.self))."
|
||||
)
|
||||
result = SaveResult(saveError)
|
||||
return
|
||||
}
|
||||
|
||||
if let parentContext = self.parentContext where self.shouldCascadeSavesToParent {
|
||||
if let parentContext = self.parent, self.shouldCascadeSavesToParent {
|
||||
|
||||
switch parentContext.saveSynchronously(waitForMerge: waitForMerge) {
|
||||
|
||||
case .Success:
|
||||
case .success:
|
||||
result = SaveResult(hasChanges: true)
|
||||
|
||||
case .Failure(let error):
|
||||
case .failure(let error):
|
||||
result = SaveResult(error)
|
||||
}
|
||||
}
|
||||
@@ -150,15 +189,15 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func saveAsynchronouslyWithCompletion(completion: ((result: SaveResult) -> Void) = { _ in }) {
|
||||
internal func saveAsynchronouslyWithCompletion(_ completion: @escaping ((_ result: SaveResult) -> Void) = { _ in }) {
|
||||
|
||||
self.performBlock {
|
||||
self.perform {
|
||||
|
||||
guard self.hasChanges else {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
DispatchQueue.main.async {
|
||||
|
||||
completion(result: SaveResult(hasChanges: false))
|
||||
completion(SaveResult(hasChanges: false))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -174,24 +213,24 @@ internal extension NSManagedObjectContext {
|
||||
let saveError = CoreStoreError(error)
|
||||
CoreStore.log(
|
||||
saveError,
|
||||
"Failed to save \(cs_typeName(NSManagedObjectContext))."
|
||||
"Failed to save \(cs_typeName(NSManagedObjectContext.self))."
|
||||
)
|
||||
GCDQueue.Main.async {
|
||||
DispatchQueue.main.async {
|
||||
|
||||
completion(result: SaveResult(saveError))
|
||||
completion(SaveResult(saveError))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if let parentContext = self.parentContext where self.shouldCascadeSavesToParent {
|
||||
if self.shouldCascadeSavesToParent, let parentContext = self.parent {
|
||||
|
||||
parentContext.saveAsynchronouslyWithCompletion(completion)
|
||||
}
|
||||
else {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
DispatchQueue.main.async {
|
||||
|
||||
completion(result: SaveResult(hasChanges: true))
|
||||
completion(SaveResult(hasChanges: true))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,7 +245,7 @@ internal extension NSManagedObjectContext {
|
||||
}
|
||||
else {
|
||||
|
||||
self.registeredObjects.forEach { self.refreshObject($0, mergeChanges: true) }
|
||||
self.registeredObjects.forEach { self.refresh($0, mergeChanges: true) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,5 +256,7 @@ internal extension NSManagedObjectContext {
|
||||
|
||||
static var parentTransaction: Void?
|
||||
static var isSavingSynchronously: Void?
|
||||
static var isTransactionContext: Void?
|
||||
static var isDataStackContext: Void?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,32 +34,34 @@ internal extension NSManagedObjectModel {
|
||||
// MARK: Internal
|
||||
|
||||
@nonobjc
|
||||
internal static func fromBundle(bundle: NSBundle, modelName: String, modelVersionHints: Set<String> = []) -> NSManagedObjectModel {
|
||||
internal static func fromBundle(_ bundle: Bundle, modelName: String, modelVersionHints: Set<String> = []) -> NSManagedObjectModel {
|
||||
|
||||
guard let modelFilePath = bundle.pathForResource(modelName, ofType: "momd") else {
|
||||
guard let modelFilePath = bundle.path(forResource: modelName, ofType: "momd") else {
|
||||
|
||||
// For users migrating from very old Xcode versions: Old xcdatamodel files are not contained inside xcdatamodeld (with a "d"), and will thus fail this check. If that was the case, create a new xcdatamodeld file and copy all contents into the new model.
|
||||
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle. \(bundle)")
|
||||
}
|
||||
|
||||
let modelFileURL = NSURL(fileURLWithPath: modelFilePath)
|
||||
let versionInfoPlistURL = modelFileURL.URLByAppendingPathComponent("VersionInfo.plist", isDirectory: false)!
|
||||
let modelFileURL = URL(fileURLWithPath: modelFilePath)
|
||||
let versionInfoPlistURL = modelFileURL.appendingPathComponent("VersionInfo.plist", isDirectory: false)
|
||||
|
||||
guard let versionInfo = NSDictionary(contentsOfURL: versionInfoPlistURL),
|
||||
guard let versionInfo = NSDictionary(contentsOf: versionInfoPlistURL),
|
||||
let versionHashes = versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject] else {
|
||||
|
||||
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel)) metadata from path \"\(versionInfoPlistURL)\".")
|
||||
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel.self)) metadata from path \"\(versionInfoPlistURL)\".")
|
||||
}
|
||||
|
||||
let modelVersions = Set(versionHashes.keys)
|
||||
let currentModelVersion: String
|
||||
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String where modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
|
||||
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String,
|
||||
modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
|
||||
|
||||
currentModelVersion = plistModelVersion
|
||||
}
|
||||
else if let resolvedVersion = modelVersions.intersect(modelVersionHints).first {
|
||||
else if let resolvedVersion = modelVersions.intersection(modelVersionHints).first {
|
||||
|
||||
CoreStore.log(
|
||||
.Warning,
|
||||
.warning,
|
||||
message: "The MigrationChain leaf versions do not include the model file's current version. Resolving to version \"\(resolvedVersion)\"."
|
||||
)
|
||||
currentModelVersion = resolvedVersion
|
||||
@@ -69,7 +71,7 @@ internal extension NSManagedObjectModel {
|
||||
if !modelVersionHints.isEmpty {
|
||||
|
||||
CoreStore.log(
|
||||
.Warning,
|
||||
.warning,
|
||||
message: "The MigrationChain leaf versions do not include any of the model file's embedded versions. Resolving to version \"\(resolvedVersion)\"."
|
||||
)
|
||||
}
|
||||
@@ -80,10 +82,10 @@ internal extension NSManagedObjectModel {
|
||||
CoreStore.abort("No model files were found in URL \"\(modelFileURL)\".")
|
||||
}
|
||||
|
||||
var modelVersionFileURL: NSURL?
|
||||
var modelVersionFileURL: URL?
|
||||
for modelVersion in modelVersions {
|
||||
|
||||
let fileURL = modelFileURL.URLByAppendingPathComponent("\(modelVersion).mom", isDirectory: false)!
|
||||
let fileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
|
||||
|
||||
if modelVersion == currentModelVersion {
|
||||
|
||||
@@ -92,13 +94,13 @@ internal extension NSManagedObjectModel {
|
||||
}
|
||||
|
||||
precondition(
|
||||
NSManagedObjectModel(contentsOfURL: fileURL) != nil,
|
||||
NSManagedObjectModel(contentsOf: fileURL) != nil,
|
||||
"Could not find the \"\(modelVersion).mom\" version file for the model at URL \"\(modelFileURL)\"."
|
||||
)
|
||||
}
|
||||
|
||||
if let modelVersionFileURL = modelVersionFileURL,
|
||||
let rootModel = NSManagedObjectModel(contentsOfURL: modelVersionFileURL) {
|
||||
let rootModel = NSManagedObjectModel(contentsOf: modelVersionFileURL) {
|
||||
|
||||
rootModel.modelVersionFileURL = modelVersionFileURL
|
||||
rootModel.modelVersions = modelVersions
|
||||
@@ -106,7 +108,7 @@ internal extension NSManagedObjectModel {
|
||||
return rootModel
|
||||
}
|
||||
|
||||
CoreStore.abort("Could not create an \(cs_typeName(NSManagedObjectModel)) from the model at URL \"\(modelFileURL)\".")
|
||||
CoreStore.abort("Could not create an \(cs_typeName(NSManagedObjectModel.self)) from the model at URL \"\(modelFileURL)\".")
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
@@ -152,7 +154,7 @@ internal extension NSManagedObjectModel {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func entityNameForClass(entityClass: AnyClass) -> String {
|
||||
internal func entityNameForClass(_ entityClass: AnyClass) -> String {
|
||||
|
||||
return self.entityNameMapping[NSStringFromClass(entityClass)]!
|
||||
}
|
||||
@@ -183,14 +185,14 @@ internal extension NSManagedObjectModel {
|
||||
}
|
||||
|
||||
guard let modelFileURL = self.modelFileURL,
|
||||
let modelVersions = self.modelVersions
|
||||
where modelVersions.contains(modelVersion) else {
|
||||
let modelVersions = self.modelVersions,
|
||||
modelVersions.contains(modelVersion) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
let versionModelFileURL = modelFileURL.URLByAppendingPathComponent("\(modelVersion).mom", isDirectory: false)
|
||||
guard let model = NSManagedObjectModel(contentsOfURL: versionModelFileURL!) else {
|
||||
let versionModelFileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
|
||||
guard let model = NSManagedObjectModel(contentsOf: versionModelFileURL) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -202,15 +204,15 @@ internal extension NSManagedObjectModel {
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal subscript(metadata: [String: AnyObject]) -> NSManagedObjectModel? {
|
||||
internal subscript(metadata: [String: Any]) -> NSManagedObjectModel? {
|
||||
|
||||
guard let modelHashes = metadata[NSStoreModelVersionHashesKey] as? [String : NSData] else {
|
||||
guard let modelHashes = metadata[NSStoreModelVersionHashesKey] as? [String : Data] else {
|
||||
|
||||
return nil
|
||||
}
|
||||
for modelVersion in self.modelVersions ?? [] {
|
||||
|
||||
if let versionModel = self[modelVersion] where modelHashes == versionModel.entityVersionHashesByName {
|
||||
if let versionModel = self[modelVersion], modelHashes == versionModel.entityVersionHashesByName {
|
||||
|
||||
return versionModel
|
||||
}
|
||||
@@ -222,16 +224,16 @@ internal extension NSManagedObjectModel {
|
||||
// MARK: Private
|
||||
|
||||
@nonobjc
|
||||
private var modelFileURL: NSURL? {
|
||||
private var modelFileURL: URL? {
|
||||
|
||||
get {
|
||||
|
||||
return self.modelVersionFileURL?.URLByDeletingLastPathComponent
|
||||
return self.modelVersionFileURL?.deletingLastPathComponent()
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
private var modelVersionFileURL: NSURL? {
|
||||
private var modelVersionFileURL: URL? {
|
||||
|
||||
get {
|
||||
|
||||
@@ -239,12 +241,12 @@ internal extension NSManagedObjectModel {
|
||||
&PropertyKeys.modelVersionFileURL,
|
||||
inObject: self
|
||||
)
|
||||
return value
|
||||
return value as URL?
|
||||
}
|
||||
set {
|
||||
|
||||
cs_setAssociatedCopiedObject(
|
||||
newValue,
|
||||
newValue as NSURL?,
|
||||
forKey: &PropertyKeys.modelVersionFileURL,
|
||||
inObject: self
|
||||
)
|
||||
@@ -270,7 +272,7 @@ internal extension NSManagedObjectModel {
|
||||
}
|
||||
|
||||
let className = $0.managedObjectClassName
|
||||
mapping[className] = entityName
|
||||
mapping[className!] = entityName
|
||||
}
|
||||
cs_setAssociatedCopiedObject(
|
||||
mapping as NSDictionary,
|
||||
|
||||
@@ -66,15 +66,15 @@ internal extension NSPersistentStore {
|
||||
|
||||
// MARK: - StorageObject
|
||||
|
||||
private class StorageObject: NSObject {
|
||||
fileprivate class StorageObject: NSObject {
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@nonobjc
|
||||
private let storageInterface: StorageInterface?
|
||||
fileprivate let storageInterface: StorageInterface?
|
||||
|
||||
@nonobjc
|
||||
private init(_ storage: StorageInterface?) {
|
||||
fileprivate init(_ storage: StorageInterface?) {
|
||||
|
||||
self.storageInterface = storage
|
||||
}
|
||||
|
||||
@@ -26,134 +26,53 @@
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
#if USE_FRAMEWORKS
|
||||
import GCDKit
|
||||
#endif
|
||||
|
||||
|
||||
// MARK: - NSPersistentStoreCoordinator
|
||||
|
||||
internal extension NSPersistentStoreCoordinator {
|
||||
|
||||
@nonobjc
|
||||
internal func performAsynchronously(closure: () -> Void) {
|
||||
internal func performAsynchronously(_ closure: @escaping () -> Void) {
|
||||
|
||||
#if USE_FRAMEWORKS
|
||||
|
||||
self.performBlock(closure)
|
||||
#else
|
||||
|
||||
if #available(iOS 8.0, *) {
|
||||
|
||||
self.performBlock(closure)
|
||||
}
|
||||
else {
|
||||
|
||||
self.lock()
|
||||
GCDQueue.Default.async {
|
||||
|
||||
closure()
|
||||
self.unlock()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
self.perform(closure)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func performSynchronously<T>(closure: () -> T) -> T {
|
||||
internal func performSynchronously<T>(_ closure: @escaping () -> T) -> T {
|
||||
|
||||
var result: T?
|
||||
#if USE_FRAMEWORKS
|
||||
self.performAndWait {
|
||||
|
||||
self.performBlockAndWait {
|
||||
|
||||
result = closure()
|
||||
}
|
||||
#else
|
||||
|
||||
if #available(iOS 8.0, *) {
|
||||
|
||||
self.performBlockAndWait {
|
||||
|
||||
result = closure()
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
self.lock()
|
||||
cs_autoreleasepool {
|
||||
|
||||
result = closure()
|
||||
}
|
||||
self.unlock()
|
||||
}
|
||||
#endif
|
||||
|
||||
result = closure()
|
||||
}
|
||||
return result!
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func performSynchronously<T>(closure: () throws -> T) throws -> T {
|
||||
internal func performSynchronously<T>(_ closure: @escaping () throws -> T) throws -> T {
|
||||
|
||||
var closureError: ErrorType?
|
||||
var closureError: Error?
|
||||
var result: T?
|
||||
#if USE_FRAMEWORKS
|
||||
self.performAndWait {
|
||||
|
||||
self.performBlockAndWait {
|
||||
do {
|
||||
|
||||
do {
|
||||
|
||||
result = try closure()
|
||||
}
|
||||
catch {
|
||||
|
||||
closureError = error
|
||||
}
|
||||
result = try closure()
|
||||
}
|
||||
#else
|
||||
|
||||
if #available(iOS 8.0, *) {
|
||||
catch {
|
||||
|
||||
self.performBlockAndWait {
|
||||
|
||||
do {
|
||||
|
||||
result = try closure()
|
||||
}
|
||||
catch {
|
||||
|
||||
closureError = error
|
||||
}
|
||||
}
|
||||
closureError = error
|
||||
}
|
||||
else {
|
||||
|
||||
self.lock()
|
||||
cs_autoreleasepool {
|
||||
|
||||
do {
|
||||
|
||||
result = try closure()
|
||||
}
|
||||
catch {
|
||||
|
||||
closureError = error
|
||||
}
|
||||
}
|
||||
self.unlock()
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
if let closureError = closureError {
|
||||
|
||||
throw closureError
|
||||
}
|
||||
|
||||
return result!
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func addPersistentStoreSynchronously(storeType: String, configuration: String?, URL storeURL: NSURL?, options: [NSObject : AnyObject]?) throws -> NSPersistentStore {
|
||||
internal func addPersistentStoreSynchronously(_ storeType: String, configuration: String?, URL storeURL: URL?, options: [NSObject : AnyObject]?) throws -> NSPersistentStore {
|
||||
|
||||
var store: NSPersistentStore?
|
||||
var storeError: NSError?
|
||||
@@ -161,10 +80,10 @@ internal extension NSPersistentStoreCoordinator {
|
||||
|
||||
do {
|
||||
|
||||
store = try self.addPersistentStoreWithType(
|
||||
storeType,
|
||||
configuration: configuration,
|
||||
URL: storeURL,
|
||||
store = try self.addPersistentStore(
|
||||
ofType: storeType,
|
||||
configurationName: configuration,
|
||||
at: storeURL,
|
||||
options: options
|
||||
)
|
||||
}
|
||||
@@ -173,12 +92,10 @@ internal extension NSPersistentStoreCoordinator {
|
||||
storeError = error as NSError
|
||||
}
|
||||
}
|
||||
|
||||
if let store = store {
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
throw CoreStoreError(storeError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,18 +34,18 @@ internal final class NotificationObserver {
|
||||
|
||||
let observer: NSObjectProtocol
|
||||
|
||||
init(notificationName: String, object: AnyObject?, queue: NSOperationQueue? = nil, closure: (note: NSNotification) -> Void) {
|
||||
init(notificationName: Notification.Name, object: Any?, queue: OperationQueue? = nil, closure: @escaping (_ note: Notification) -> Void) {
|
||||
|
||||
self.observer = NSNotificationCenter.defaultCenter().addObserverForName(
|
||||
notificationName,
|
||||
self.observer = NotificationCenter.default.addObserver(
|
||||
forName: notificationName,
|
||||
object: object,
|
||||
queue: queue,
|
||||
usingBlock: closure
|
||||
using: closure
|
||||
)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
NSNotificationCenter.defaultCenter().removeObserver(self.observer)
|
||||
NotificationCenter.default.removeObserver(self.observer)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user