diff --git a/.travis.yml b/.travis.yml index 0726b0d..c8ad56e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode9 +osx_image: xcode10 sudo: false git: submodules: false @@ -10,17 +10,17 @@ env: - LC_CTYPE=en_US.UTF-8 - LANG=en_US.UTF-8 matrix: - - DESTINATION="OS=11.0,name=iPhone 8" SCHEME="CoreStore iOS" SDK=iphonesimulator11.0 RUN_TESTS="YES" POD_LINT="NO" - - DESTINATION="OS=10.3,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator11.0 RUN_TESTS="YES" POD_LINT="NO" - - DESTINATION="OS=10.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator11.0 RUN_TESTS="YES" POD_LINT="NO" - - DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator11.0 RUN_TESTS="YES" POD_LINT="NO" - - DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.13 RUN_TESTS="YES" POD_LINT="NO" - - DESTINATION="OS=4.0,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator4.0 RUN_TESTS="NO" POD_LINT="NO" - - DESTINATION="OS=3.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator4.0 RUN_TESTS="NO" POD_LINT="NO" - - DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator4.0 RUN_TESTS="NO" POD_LINT="NO" - - DESTINATION="OS=11.0,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator11.0 RUN_TESTS="YES" POD_LINT="NO" - - DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator11.0 RUN_TESTS="YES" POD_LINT="NO" - - DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator11.0 RUN_TESTS="YES" POD_LINT="NO" + - DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.14 RUN_TESTS="YES" POD_LINT="NO" + - DESTINATION="OS=12.0,name=iPhone XS" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO" + - DESTINATION="OS=11.0.1,name=iPhone 8" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO" + - DESTINATION="OS=10.3.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO" + - DESTINATION="OS=10.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO" + - DESTINATION="OS=4.0,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO" + - DESTINATION="OS=3.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO" + - DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO" + - DESTINATION="OS=12.0,name=Apple TV 4K" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO" + - DESTINATION="OS=11.0,name=Apple TV 4K (at 1080p)" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO" + - DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO" before_install: - gem install cocoapods --no-rdoc --no-ri --no-document --quiet - gem install xcpretty --no-rdoc --no-ri --no-document --quiet @@ -39,8 +39,8 @@ script: xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c; xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c; fi - - xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStoreDemo" -sdk "iphonesimulator11.0" -destination "OS=11.0,name=iPhone 8" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty -c; - - xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStoreDemo" -sdk "iphonesimulator11.0" -destination "OS=11.0,name=iPhone 8" -configuration Release ONLY_ACTIVE_ARCH=NO build | xcpretty -c; + - xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStoreDemo" -sdk "iphonesimulator12.0" -destination "OS=11.0.1,name=iPhone 8" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty -c; + - xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStoreDemo" -sdk "iphonesimulator12.0" -destination "OS=11.0.1,name=iPhone 8" -configuration Release ONLY_ACTIVE_ARCH=NO build | xcpretty -c; - if [ $POD_LINT == "YES" ]; then pod lib lint --quick; fi diff --git a/Sources/CustomSchemaMappingProvider.swift b/Sources/CustomSchemaMappingProvider.swift index f4a90a7..505e530 100644 --- a/Sources/CustomSchemaMappingProvider.swift +++ b/Sources/CustomSchemaMappingProvider.swift @@ -121,24 +121,24 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { // MARK: Equatable - public static func == (lhs: CustomMapping, rhs: CustomMapping) -> Bool { + public static func ==(lhs: CustomMapping, rhs: CustomMapping) -> Bool { switch (lhs, rhs) { - + case (.deleteEntity(let sourceEntity1), .deleteEntity(let sourceEntity2)): return sourceEntity1 == sourceEntity2 - + case (.insertEntity(let destinationEntity1), .insertEntity(let destinationEntity2)): return destinationEntity1 == destinationEntity2 - + case (.copyEntity(let sourceEntity1, let destinationEntity1), .copyEntity(let sourceEntity2, let destinationEntity2)): return sourceEntity1 == sourceEntity2 && destinationEntity1 == destinationEntity2 - + case (.transformEntity(let sourceEntity1, let destinationEntity1, _), .transformEntity(let sourceEntity2, let destinationEntity2, _)): return sourceEntity1 == sourceEntity2 && destinationEntity1 == destinationEntity2 - + default: return false } @@ -146,24 +146,24 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { // MARK: Hashable - + public func hash(into hasher: inout Hasher) { switch self { - + case .deleteEntity(let sourceEntity): hasher.combine(0) hasher.combine(sourceEntity) - + case .insertEntity(let destinationEntity): hasher.combine(1) hasher.combine(destinationEntity) - + case .copyEntity(let sourceEntity, let destinationEntity): hasher.combine(2) hasher.combine(sourceEntity) hasher.combine(destinationEntity) - + case .transformEntity(let sourceEntity, let destinationEntity, _): hasher.combine(3) hasher.combine(sourceEntity) @@ -177,12 +177,12 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { fileprivate var entityMappingSourceEntity: EntityName? { switch self { - + case .deleteEntity(let sourceEntity), .copyEntity(let sourceEntity, _), .transformEntity(let sourceEntity, _, _): return sourceEntity - + case .insertEntity: return nil } @@ -191,12 +191,12 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { fileprivate var entityMappingDestinationEntity: EntityName? { switch self { - + case .insertEntity(let destinationEntity), .copyEntity(_, let destinationEntity), .transformEntity(_, let destinationEntity, _): return destinationEntity - + case .deleteEntity: return nil } @@ -324,7 +324,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { // MARK: Equatable - public static func == (lhs: CustomSchemaMappingProvider, rhs: CustomSchemaMappingProvider) -> Bool { + public static func ==(lhs: CustomSchemaMappingProvider, rhs: CustomSchemaMappingProvider) -> Bool { return lhs.sourceVersion == rhs.sourceVersion && lhs.destinationVersion == rhs.destinationVersion @@ -333,9 +333,9 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { // MARK: Hashable - + public func hash(into hasher: inout Hasher) { - + hasher.combine(self.sourceVersion) hasher.combine(self.destinationVersion) hasher.combine(ObjectIdentifier(cs_dynamicType(of: self))) @@ -422,8 +422,8 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { entityMapping.sourceExpression = expression(forSource: sourceEntity) entityMapping.attributeMappings = autoreleasepool { () -> [NSPropertyMapping] in - let sourceAttributes = sourceEntity.cs_resolvedAttributeRenamingIdentities() - let destinationAttributes = destinationEntity.cs_resolvedAttributeRenamingIdentities() + let sourceAttributes = sourceEntity.cs_resolveAttributeNames() + let destinationAttributes = destinationEntity.cs_resolveAttributeRenamingIdentities() var attributeMappings: [NSPropertyMapping] = [] for (renamingIdentifier, destination) in destinationAttributes { @@ -439,15 +439,15 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { } entityMapping.relationshipMappings = autoreleasepool { () -> [NSPropertyMapping] in - let sourceRelationships = sourceEntity.cs_resolvedRelationshipRenamingIdentities() - let destinationRelationships = destinationEntity.cs_resolvedRelationshipRenamingIdentities() + let sourceRelationships = sourceEntity.cs_resolveRelationshipNames() + let destinationRelationships = destinationEntity.cs_resolveRelationshipRenamingIdentities() var relationshipMappings: [NSPropertyMapping] = [] for (renamingIdentifier, destination) in destinationRelationships { let sourceRelationship = sourceRelationships[renamingIdentifier]!.relationship let destinationRelationship = destination.relationship let sourceRelationshipName = sourceRelationship.name - + let propertyMapping = NSPropertyMapping() propertyMapping.name = destinationRelationship.name propertyMapping.valueExpression = NSExpression(format: "FUNCTION($\(NSMigrationManagerKey), \"destinationInstancesForSourceRelationshipNamed:sourceInstances:\", \"\(sourceRelationshipName)\", FUNCTION($\(NSMigrationSourceObjectKey), \"\(#selector(NSManagedObject.value(forKey:)))\", \"\(sourceRelationshipName)\"))") @@ -476,12 +476,12 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { ] autoreleasepool { - let sourceAttributes = sourceEntity.cs_resolvedAttributeRenamingIdentities() - let destinationAttributes = destinationEntity.cs_resolvedAttributeRenamingIdentities() + let sourceAttributes = sourceEntity.cs_resolveAttributeNames() + let destinationAttributes = destinationEntity.cs_resolveAttributeRenamingIdentities() let transformedRenamingIdentifiers = Set(destinationAttributes.keys) .intersection(sourceAttributes.keys) - + var sourceAttributesByDestinationKey: [KeyPathString: NSAttributeDescription] = [:] for renamingIdentifier in transformedRenamingIdentifiers { @@ -493,19 +493,19 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { } entityMapping.relationshipMappings = autoreleasepool { () -> [NSPropertyMapping] in - let sourceRelationships = sourceEntity.cs_resolvedRelationshipRenamingIdentities() - let destinationRelationships = destinationEntity.cs_resolvedRelationshipRenamingIdentities() + let sourceRelationships = sourceEntity.cs_resolveRelationshipNames() + let destinationRelationships = destinationEntity.cs_resolveRelationshipRenamingIdentities() let transformedRenamingIdentifiers = Set(destinationRelationships.keys) .intersection(sourceRelationships.keys) - + var relationshipMappings: [NSPropertyMapping] = [] for renamingIdentifier in transformedRenamingIdentifiers { - + let sourceRelationship = sourceRelationships[renamingIdentifier]!.relationship let destinationRelationship = destinationRelationships[renamingIdentifier]!.relationship let sourceRelationshipName = sourceRelationship.name let destinationRelationshipName = destinationRelationship.name - + let propertyMapping = NSPropertyMapping() propertyMapping.name = destinationRelationshipName propertyMapping.valueExpression = NSExpression(format: "FUNCTION($\(NSMigrationManagerKey), \"destinationInstancesForSourceRelationshipNamed:sourceInstances:\", \"\(sourceRelationshipName)\", FUNCTION($\(NSMigrationSourceObjectKey), \"\(#selector(NSManagedObject.value(forKey:)))\", \"\(sourceRelationshipName)\"))") @@ -593,9 +593,9 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { var allMappedSourceKeys: [KeyPathString: KeyPathString] = [:] var allMappedDestinationKeys: [KeyPathString: KeyPathString] = [:] - let sourceRenamingIdentifiers = sourceModel.cs_resolvedRenamingIdentities() + let sourceRenamingIdentifiers = sourceModel.cs_resolveNames() let sourceEntityNames = sourceModel.entitiesByName - let destinationRenamingIdentifiers = destinationModel.cs_resolvedRenamingIdentities() + let destinationRenamingIdentifiers = destinationModel.cs_resolveRenamingIdentities() let destinationEntityNames = destinationModel.entitiesByName let removedRenamingIdentifiers = Set(sourceRenamingIdentifiers.keys) @@ -610,7 +610,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { for mapping in self.entityMappings { switch mapping { - + case .deleteEntity(let sourceEntity): CoreStore.assert( sourceEntityNames[sourceEntity] != nil, @@ -622,7 +622,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { ) deleteMappings.insert(mapping) allMappedSourceKeys[sourceEntity] = "" - + case .insertEntity(let destinationEntity): CoreStore.assert( destinationEntityNames[destinationEntity] != nil, @@ -634,7 +634,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { ) insertMappings.insert(mapping) allMappedDestinationKeys[destinationEntity] = "" - + case .transformEntity(let sourceEntity, let destinationEntity, _): CoreStore.assert( sourceEntityNames[sourceEntity] != nil, @@ -655,7 +655,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { transformMappings.insert(mapping) allMappedSourceKeys[sourceEntity] = destinationEntity allMappedDestinationKeys[destinationEntity] = sourceEntity - + case .copyEntity(let sourceEntity, let destinationEntity): CoreStore.assert( sourceEntityNames[sourceEntity] != nil, @@ -689,7 +689,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { let sourceEntityName = sourceEntity.name! let destinationEntityName = destinationEntity.name! switch (allMappedSourceKeys[sourceEntityName], allMappedDestinationKeys[destinationEntityName]) { - + case (nil, nil): if sourceEntity.versionHash == destinationEntity.versionHash { @@ -699,8 +699,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { destinationEntity: destinationEntityName ) ) - } - else { + } else { transformMappings.insert( .transformEntity( @@ -712,15 +711,15 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { } allMappedSourceKeys[sourceEntityName] = destinationEntityName allMappedDestinationKeys[destinationEntityName] = sourceEntityName - + case (""?, nil): insertMappings.insert(.insertEntity(destinationEntity: destinationEntityName)) allMappedDestinationKeys[destinationEntityName] = "" - + case (nil, ""?): deleteMappings.insert(.deleteEntity(sourceEntity: sourceEntityName)) allMappedSourceKeys[sourceEntityName] = "" - + default: continue } @@ -730,11 +729,11 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { let sourceEntity = sourceRenamingIdentifiers[renamingIdentifier]!.entity let sourceEntityName = sourceEntity.name! switch allMappedSourceKeys[sourceEntityName] { - + case nil: deleteMappings.insert(.deleteEntity(sourceEntity: sourceEntityName)) allMappedSourceKeys[sourceEntityName] = "" - + default: continue } @@ -744,11 +743,11 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { let destinationEntity = destinationRenamingIdentifiers[renamingIdentifier]!.entity let destinationEntityName = destinationEntity.name! switch allMappedDestinationKeys[destinationEntityName] { - + case nil: insertMappings.insert(.insertEntity(destinationEntity: destinationEntityName)) allMappedDestinationKeys[destinationEntityName] = "" - + default: continue } diff --git a/Sources/NSEntityDescription+Migration.swift b/Sources/NSEntityDescription+Migration.swift index 6d9705d..ddeb09d 100644 --- a/Sources/NSEntityDescription+Migration.swift +++ b/Sources/NSEntityDescription+Migration.swift @@ -32,24 +32,30 @@ import Foundation internal extension NSEntityDescription { @nonobjc - internal func cs_resolvedAttributeRenamingIdentities() -> [String: (attribute: NSAttributeDescription, versionHash: Data)] { - - var mapping: [String: (attribute: NSAttributeDescription, versionHash: Data)] = [:] - for (attributeName, attributeDescription) in self.attributesByName { - - mapping[attributeDescription.renamingIdentifier ?? attributeName] = (attributeDescription, attributeDescription.versionHash) - } - return mapping + internal func cs_resolveAttributeNames() -> [String: (attribute: NSAttributeDescription, versionHash: Data)] { + return self.attributesByName.reduce(into: [:], { (result, attribute: (name: String, description: NSAttributeDescription)) in + result[attribute.name] = (attribute.description, attribute.description.versionHash) + }) } @nonobjc - internal func cs_resolvedRelationshipRenamingIdentities() -> [String: (relationship: NSRelationshipDescription, versionHash: Data)] { - - var mapping: [String: (relationship: NSRelationshipDescription, versionHash: Data)] = [:] - for (relationshipName, relationshipDescription) in self.relationshipsByName { - - mapping[relationshipDescription.renamingIdentifier ?? relationshipName] = (relationshipDescription, relationshipDescription.versionHash) - } - return mapping + internal func cs_resolveAttributeRenamingIdentities() -> [String: (attribute: NSAttributeDescription, versionHash: Data)] { + return self.attributesByName.reduce(into: [:], { (result, attribute: (name: String, description: NSAttributeDescription)) in + result[attribute.description.renamingIdentifier ?? attribute.name] = (attribute.description, attribute.description.versionHash) + }) + } + + @nonobjc + internal func cs_resolveRelationshipNames() -> [String: (relationship: NSRelationshipDescription, versionHash: Data)] { + return self.relationshipsByName.reduce(into: [:], { (result, relationship: (name: String, description: NSRelationshipDescription)) in + result[relationship.name] = (relationship.description, relationship.description.versionHash) + }) + } + + @nonobjc + internal func cs_resolveRelationshipRenamingIdentities() -> [String: (relationship: NSRelationshipDescription, versionHash: Data)] { + return self.relationshipsByName.reduce(into: [:], { (result, relationship: (name: String, description: NSRelationshipDescription)) in + result[relationship.description.renamingIdentifier ?? relationship.name] = (relationship.description, relationship.description.versionHash) + }) } } diff --git a/Sources/NSManagedObjectModel+Migration.swift b/Sources/NSManagedObjectModel+Migration.swift index 438ab2f..7bbc0d2 100644 --- a/Sources/NSManagedObjectModel+Migration.swift +++ b/Sources/NSManagedObjectModel+Migration.swift @@ -32,13 +32,16 @@ import Foundation internal extension NSManagedObjectModel { @nonobjc - internal func cs_resolvedRenamingIdentities() -> [String: (entity: NSEntityDescription, versionHash: Data)] { - - var mapping: [String: (entity: NSEntityDescription, versionHash: Data)] = [:] - for (entityName, entityDescription) in self.entitiesByName { - - mapping[entityDescription.renamingIdentifier ?? entityName] = (entityDescription, entityDescription.versionHash) - } - return mapping + internal func cs_resolveNames() -> [String: (entity: NSEntityDescription, versionHash: Data)] { + return self.entitiesByName.reduce(into: [:], { (result, entity: (name: String, description: NSEntityDescription)) in + result[entity.name] = (entity.description, entity.description.versionHash) + }) + } + + @nonobjc + internal func cs_resolveRenamingIdentities() -> [String: (entity: NSEntityDescription, versionHash: Data)] { + return self.entitiesByName.reduce(into: [:], { (result, entity: (name: String, description: NSEntityDescription)) in + result[entity.description.renamingIdentifier ?? entity.name] = (entity.description, entity.description.versionHash) + }) } }