migration utilities (beta), swift 2 conversion

This commit is contained in:
John Rommel Estropia
2015-07-07 08:03:46 +09:00
parent bf0eebe057
commit 5b85b0749e
59 changed files with 1319 additions and 733 deletions

View File

@@ -42,27 +42,27 @@ internal func getAssociatedObjectForKey<T: AnyObject>(key: UnsafePointer<Void>,
internal func setAssociatedRetainedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
objc_setAssociatedObject(object, key, associatedObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
internal func setAssociatedCopiedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_COPY_NONATOMIC))
objc_setAssociatedObject(object, key, associatedObject, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
internal func setAssociatedAssignedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_ASSIGN))
objc_setAssociatedObject(object, key, associatedObject, .OBJC_ASSOCIATION_ASSIGN)
}
internal func setAssociatedWeakObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
if let associatedObject = associatedObject {
objc_setAssociatedObject(object, key, WeakObject(associatedObject), UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
objc_setAssociatedObject(object, key, WeakObject(associatedObject), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
else {
objc_setAssociatedObject(object, key, nil, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
objc_setAssociatedObject(object, key, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}

View File

@@ -35,7 +35,7 @@ internal extension NSManagedObject {
internal dynamic class func createInContext(context: NSManagedObjectContext) -> Self {
return self(
return self.init(
entity: context.entityDescriptionForEntityType(self)!,
insertIntoManagedObjectContext: context
)
@@ -61,16 +61,19 @@ internal extension NSManagedObject {
private class func typedObjectInContext<T: NSManagedObject>(context: NSManagedObjectContext, objectID: NSManagedObjectID) -> T? {
var error: NSError?
if let existingObject = context.existingObjectWithID(objectID, error: &error) {
do {
let existingObject = try context.existingObjectWithID(objectID)
return (existingObject as! T)
}
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to load existing \(typeName(self)) in context.")
return nil;
catch {
CoreStore.handleError(
error as NSError,
"Failed to load existing \(typeName(self)) in context."
)
return nil
}
}
private func typedObjectInContext<T: NSManagedObject>(context: NSManagedObjectContext) -> T? {
@@ -78,29 +81,42 @@ internal extension NSManagedObject {
let objectID = self.objectID
if objectID.temporaryID {
var error: NSError?
let didSucceed = withExtendedLifetime(self.managedObjectContext) {
var objectIDError: NSError?
let didSucceed = withExtendedLifetime(self.managedObjectContext) { (context: NSManagedObjectContext?) -> Bool in
return $0?.obtainPermanentIDsForObjects([self], error: &error)
do {
try context?.obtainPermanentIDsForObjects([self])
return true
}
catch {
objectIDError = error as NSError
return false
}
}
if didSucceed != true {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to obtain permanent ID for object.")
objectIDError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to obtain permanent ID for object."
)
return nil
}
}
var error: NSError?
if let existingObject = context.existingObjectWithID(objectID, error: &error) {
do {
let existingObject = try context.existingObjectWithID(objectID)
return (existingObject as! T)
}
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to load existing \(typeName(self)) in context.")
return nil;
catch {
CoreStore.handleError(
error as NSError,
"Failed to load existing \(typeName(self)) in context."
)
return nil
}
}
}

View File

@@ -73,10 +73,7 @@ internal extension NSManagedObjectContext {
internal func setupForCoreStoreWithContextName(contextName: String) {
if self.respondsToSelector("setName:") {
self.name = contextName
}
self.name = contextName
self.observerForWillSaveNotification = NotificationObserver(
notificationName: NSManagedObjectContextWillSaveNotification,
@@ -91,16 +88,18 @@ internal extension NSManagedObjectContext {
return
}
var error: NSError?
if context.obtainPermanentIDsForObjects(Array(insertedObjects), error: &error) {
do {
try context.obtainPermanentIDsForObjects(Array(insertedObjects))
return
}
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed to obtain permanent ID(s) for \(numberOfInsertedObjects) inserted object(s)."
)
catch {
CoreStore.handleError(
error as NSError,
"Failed to obtain permanent ID(s) for \(numberOfInsertedObjects) inserted object(s)."
)
}
}
)
}

View File

@@ -52,16 +52,24 @@ internal extension NSManagedObjectContext {
}
var fetchResults: [T]?
var error: NSError?
var fetchError: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T]
do {
fetchResults = try self.executeFetchRequest(fetchRequest) as? [T]
}
catch {
fetchError = error as NSError
}
}
if fetchResults == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
fetchError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request."
)
return nil
}
@@ -87,16 +95,24 @@ internal extension NSManagedObjectContext {
}
var fetchResults: [T]?
var error: NSError?
var fetchError: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T]
do {
fetchResults = try self.executeFetchRequest(fetchRequest) as? [T]
}
catch {
fetchError = error as NSError
}
}
if fetchResults == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
fetchError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request."
)
return nil
}
@@ -128,7 +144,8 @@ internal extension NSManagedObjectContext {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
"Failed executing fetch request."
)
return nil
}
@@ -154,16 +171,24 @@ internal extension NSManagedObjectContext {
}
var fetchResults: [NSManagedObjectID]?
var error: NSError?
var fetchError: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObjectID]
do {
fetchResults = try self.executeFetchRequest(fetchRequest) as? [NSManagedObjectID]
}
catch {
fetchError = error as NSError
}
}
if fetchResults == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
fetchError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request."
)
return nil
}
@@ -189,16 +214,24 @@ internal extension NSManagedObjectContext {
}
var fetchResults: [NSManagedObjectID]?
var error: NSError?
var fetchError: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObjectID]
do {
fetchResults = try self.executeFetchRequest(fetchRequest) as? [NSManagedObjectID]
}
catch {
fetchError = error as NSError
}
}
if fetchResults == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
fetchError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request."
)
return nil
}
@@ -225,26 +258,32 @@ internal extension NSManagedObjectContext {
}
var numberOfDeletedObjects: Int?
var error: NSError?
var fetchError: NSError?
self.performBlockAndWait {
autoreleasepool {
if let fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [T] {
do {
numberOfDeletedObjects = fetchResults.count
let fetchResults = try self.executeFetchRequest(fetchRequest) as? [T] ?? []
for object in fetchResults {
self.deleteObject(object)
}
numberOfDeletedObjects = fetchResults.count
}
catch {
fetchError = error as NSError
}
}
}
if numberOfDeletedObjects == nil {
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
fetchError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request."
)
return nil
}
@@ -271,10 +310,17 @@ internal extension NSManagedObjectContext {
}
var fetchResults: [AnyObject]?
var error: NSError?
var fetchError: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error)
do {
fetchResults = try self.executeFetchRequest(fetchRequest)
}
catch {
fetchError = error as NSError
}
}
if let fetchResults = fetchResults {
@@ -287,8 +333,9 @@ internal extension NSManagedObjectContext {
}
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
fetchError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request."
)
return nil
}
@@ -312,10 +359,17 @@ internal extension NSManagedObjectContext {
}
var fetchResults: [AnyObject]?
var error: NSError?
var fetchError: NSError?
self.performBlockAndWait {
fetchResults = self.executeFetchRequest(fetchRequest, error: &error)
do {
fetchResults = try self.executeFetchRequest(fetchRequest)
}
catch {
fetchError = error as NSError
}
}
if let fetchResults = fetchResults {
@@ -323,8 +377,9 @@ internal extension NSManagedObjectContext {
}
CoreStore.handleError(
error ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request.")
fetchError ?? NSError(coreStoreErrorCode: .UnknownError),
"Failed executing fetch request."
)
return nil
}
}

View File

@@ -68,44 +68,43 @@ internal extension NSManagedObjectContext {
internal func saveSynchronously() -> SaveResult {
var result = SaveResult(hasChanges: false)
self.performBlockAndWait {
[unowned self] () -> Void in
self.performBlockAndWait { [unowned self] () -> Void in
if !self.hasChanges {
return
}
var saveError: NSError?
if self.save(&saveError) {
do {
if self.shouldCascadeSavesToParent {
if let parentContext = self.parentContext {
switch parentContext.saveSynchronously() {
case .Success(let hasChanges):
result = SaveResult(hasChanges: true)
case .Failure(let error):
result = SaveResult(error)
}
return
}
}
result = SaveResult(hasChanges: true)
try self.save()
}
else if let error = saveError {
catch {
let saveError = error as NSError
CoreStore.handleError(
error,
"Failed to save <\(NSManagedObjectContext.self)>.")
result = SaveResult(error)
saveError,
"Failed to save \(typeName(NSManagedObjectContext))."
)
result = SaveResult(saveError)
return
}
if let parentContext = self.parentContext where self.shouldCascadeSavesToParent {
switch parentContext.saveSynchronously() {
case .Success:
result = SaveResult(hasChanges: true)
case .Failure(let error):
result = SaveResult(error)
}
}
else {
result = SaveResult(hasChanges: false)
result = SaveResult(hasChanges: true)
}
}
@@ -128,43 +127,35 @@ internal extension NSManagedObjectContext {
return
}
var saveError: NSError?
if self.save(&saveError) {
do {
if self.shouldCascadeSavesToParent {
if let parentContext = self.parentContext {
let result = parentContext.saveSynchronously()
if let completion = completion {
GCDQueue.Main.async {
completion(result: result)
}
}
return
}
}
if let completion = completion {
GCDQueue.Main.async {
completion(result: SaveResult(hasChanges: true))
}
}
try self.save()
}
else if let error = saveError {
catch {
let saveError = error as NSError
CoreStore.handleError(
error,
"Failed to save <\(NSManagedObjectContext.self)>.")
saveError,
"Failed to save \(typeName(NSManagedObjectContext))."
)
if let completion = completion {
GCDQueue.Main.async {
completion(result: SaveResult(error))
completion(result: SaveResult(saveError))
}
}
return
}
if let parentContext = self.parentContext where self.shouldCascadeSavesToParent {
let result = parentContext.saveSynchronously()
if let completion = completion {
GCDQueue.Main.async {
completion(result: result)
}
}
}
@@ -172,7 +163,7 @@ internal extension NSManagedObjectContext {
GCDQueue.Main.async {
completion(result: SaveResult(hasChanges: false))
completion(result: SaveResult(hasChanges: true))
}
}
}

View File

@@ -33,25 +33,177 @@ internal extension NSManagedObjectModel {
// MARK: Internal
private var modelFileURL: NSURL? {
get {
return self.modelVersionFileURL?.URLByDeletingLastPathComponent
}
}
private(set) var currentModelVersion: String? {
get {
let value: NSString? = getAssociatedObjectForKey(
&PropertyKeys.currentModelVersion,
inObject: self
)
return value as? String
}
set {
setAssociatedCopiedObject(
newValue == nil ? nil : (newValue! as NSString),
forKey: &PropertyKeys.currentModelVersion,
inObject: self
)
}
}
private(set) var modelVersions: Set<String>? {
get {
let value: NSSet? = getAssociatedObjectForKey(
&PropertyKeys.modelVersions,
inObject: self
)
return value as? Set<String>
}
set {
setAssociatedCopiedObject(
newValue == nil ? nil : (newValue! as NSSet),
forKey: &PropertyKeys.modelVersions,
inObject: self
)
}
}
func entityNameForClass(entityClass: AnyClass) -> String {
return self.entityNameMapping[NSStringFromClass(entityClass)]!
}
func configurationsForClass(entityClass: AnyClass) -> Set<String> {
func mergedModels() -> [NSManagedObjectModel] {
return self.entityConfigurationsMapping[NSStringFromClass(entityClass)]!
return self.modelVersions?.map { self[$0] }.flatMap { $0 == nil ? [] : [$0!] } ?? [self]
}
subscript(modelVersion: String) -> NSManagedObjectModel? {
if modelVersion == self.currentModelVersion {
return self
}
guard let modelFileURL = self.modelFileURL,
let modelVersions = self.modelVersions
where modelVersions.contains(modelVersion) else {
return nil
}
let versionModelFileURL = modelFileURL.URLByAppendingPathComponent("\(modelVersion).mom", isDirectory: false)
guard let model = NSManagedObjectModel(contentsOfURL: versionModelFileURL) else {
return nil
}
model.currentModelVersion = modelVersion
model.modelVersionFileURL = versionModelFileURL
model.modelVersions = modelVersions
return model
}
class func fromBundle(bundle: NSBundle, modelName: String, modelVersion: String? = nil) -> NSManagedObjectModel {
guard let modelFilePath = bundle.pathForResource(modelName, ofType: "momd") else {
CoreStore.fatalError("Could not find \"\(modelName).momd\" from the bundle. \(bundle)")
}
let modelFileURL = NSURL(fileURLWithPath: modelFilePath)
let versionInfoPlistURL = modelFileURL.URLByAppendingPathComponent("VersionInfo.plist", isDirectory: false)
guard let versionInfo = NSDictionary(contentsOfURL: versionInfoPlistURL),
let versionHashes = versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject] else {
CoreStore.fatalError("Could not load \(typeName(NSManagedObjectModel)) metadata from path \"\(versionInfoPlistURL)\"."
)
}
let modelVersions = Set(versionHashes.keys)
let currentModelVersion: String
if let modelVersion = modelVersion {
precondition(modelVersions.contains(modelVersion))
currentModelVersion = modelVersion
}
else {
currentModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String ?? modelVersions.first!
}
var modelVersionFileURL: NSURL?
for modelVersion in modelVersions {
let fileURL = modelFileURL.URLByAppendingPathComponent("\(modelVersion).mom", isDirectory: false)
if modelVersion == currentModelVersion {
modelVersionFileURL = fileURL
continue
}
CoreStore.assert(
NSManagedObjectModel(contentsOfURL: 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) {
rootModel.modelVersionFileURL = modelVersionFileURL
rootModel.modelVersions = modelVersions
rootModel.currentModelVersion = currentModelVersion
return rootModel
}
CoreStore.fatalError("Could not create an \(typeName(NSManagedObjectModel)) from the model at URL \"\(modelFileURL)\".")
}
// MARK: Private
internal var entityNameMapping: [String: String] {
private var modelVersionFileURL: NSURL? {
get {
if let mapping: NSDictionary? = getAssociatedObjectForKey(&PropertyKeys.entityNameMapping, inObject: self) {
let value: NSURL? = getAssociatedObjectForKey(
&PropertyKeys.modelVersionFileURL,
inObject: self
)
return value
}
set {
setAssociatedCopiedObject(
newValue,
forKey: &PropertyKeys.modelVersionFileURL,
inObject: self
)
}
}
private var entityNameMapping: [String: String] {
get {
if let mapping: NSDictionary = getAssociatedObjectForKey(&PropertyKeys.entityNameMapping, inObject: self) {
return mapping as! [String: String]
}
@@ -75,25 +227,12 @@ internal extension NSManagedObjectModel {
}
}
private lazy var entityConfigurationsMapping: [String: Set<String>] = {
[unowned self] in
return self.configurations.reduce([String: Set<String>]()) {
(var mapping, configuration) -> [String: Set<String>] in
return (self.entitiesForConfiguration(configuration) ?? []).reduce(mapping) {
(var mapping, entityDescription) -> [String: Set<String>] in
let className = entityDescription.managedObjectClassName
mapping[className]?.insert(configuration)
return mapping
}
}
}()
private struct PropertyKeys {
static var entityNameMapping: Void?
static var entityConfigurationsMapping: Void?
static var modelVersionFileURL: Void?
static var modelVersions: Void?
static var currentModelVersion: Void?
}
}

View File

@@ -36,7 +36,7 @@ internal final class NotificationObserver {
let object: AnyObject?
let observer: NSObjectProtocol
init(notificationName: String, object: AnyObject?, closure: (note: NSNotification!) -> Void) {
init(notificationName: String, object: AnyObject?, closure: (note: NSNotification) -> Void) {
self.notificationName = notificationName
self.object = object

View File

@@ -1,13 +0,0 @@
//
// RootManagedObjectModel.swift
// CoreStore
//
// Created by John Rommel Estropia on 2015/07/04.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
//
import UIKit
class RootManagedObjectModel: NSManagedObjectModel {
}