使用由代码生成的NSManagedObjectModel时,NSPersistentStoreCoordinator.addPersistentStore导致异常

时间:2018-04-02 20:15:27

标签: ios core-data

仅在应用首次启动时才会出现此问题。使用NSInMemoryStoreType时出现 NOT 问题。

iOS内部处理异常并且不会导致应用程序崩溃,但我认为最好在可能的情况下将其删除。

* thread #1, queue = 'SQLQueue 0x7fb663441f20 for MyApp.sqlite', stop reason = breakpoint 1.1
  * frame #0: 0x000000010e45c001 libobjc.A.dylib`objc_exception_throw
    frame #1: 0x000000010df2ed1e Foundation`-[NSCoder(Exceptions) __failWithException:] + 136
    frame #2: 0x000000010df2ee9b Foundation`-[NSCoder(Exceptions) __failWithExceptionName:errorCode:format:] + 381
    frame #3: 0x000000010de81b26 Foundation`-[NSCoder validateClassSupportsSecureCoding:] + 326
    frame #4: 0x000000010dea52d0 Foundation`_encodeObject + 397
    frame #5: 0x000000010df57798 Foundation`+[NSKeyedArchiver(NSKeyedArchiverSecureCodingInitializers) archivedDataWithRootObject:requiringSecureCoding:error:] + 102
    frame #6: 0x00000001119a23a1 CoreData`-[NSSQLiteConnection _compressedDataWithModel:] + 65
    frame #7: 0x00000001119a262b CoreData`-[NSSQLiteConnection saveCachedModel:] + 251
    frame #8: 0x00000001119a32e7 CoreData`-[NSSQLiteConnection createSchema] + 391
    frame #9: 0x000000011184262a CoreData`-[NSSQLiteConnection connect] + 2170
    frame #10: 0x0000000111965dce CoreData`__32-[NSSQLCore _loadAndSetMetadata]_block_invoke + 158
    frame #11: 0x000000011199935e CoreData`__37-[NSSQLiteConnection performAndWait:]_block_invoke + 30
    frame #12: 0x0000000113809848 libdispatch.dylib`_dispatch_client_callout + 8
    frame #13: 0x00000001138105b8 libdispatch.dylib`_dispatch_queue_barrier_sync_invoke_and_complete + 374
    frame #14: 0x000000011199928f CoreData`-[NSSQLiteConnection performAndWait:] + 159
    frame #15: 0x0000000111841516 CoreData`-[NSSQLCore _loadAndSetMetadata] + 326
    frame #16: 0x0000000111841274 CoreData`-[NSSQLCore loadMetadata:] + 148
    frame #17: 0x0000000111949184 CoreData`__91-[NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:]_block_invoke + 1988

引发异常的原因是什么? 是NSManagedObjectModel代码(没有xcdatamodeld文件)会导致麻烦吗?

更新1

NSManagedObjectModel代码:

public class ManagedObjectModel: NSManagedObjectModel {

    public override init() {
        super.init()
        entities.append(makeFriendEntity())
        entities.append(makeProfileEntity())
        entities.append(makePostEntity())
    }

    public required init?(coder aDecoder: NSCoder) {
        fatalError()
    }
}


extension ManagedObjectModel {

    private func makeFriendEntity() -> NSEntityDescription {

        let attributeUserName = NSAttributeDescription()
        attributeUserName.name = #keyPath(FriendEntity.userName)
        attributeUserName.attributeType = .stringAttributeType
        attributeUserName.isOptional = false

        let attributeAvatarPictureURL = NSAttributeDescription()
        attributeAvatarPictureURL.name = #keyPath(FriendEntity.avatarPictureURL)
        attributeAvatarPictureURL.attributeType = .URIAttributeType
        attributeAvatarPictureURL.isOptional = false

        let attributeAvatarPictureIsSilhouette = NSAttributeDescription()
        attributeAvatarPictureIsSilhouette.name = #keyPath(FriendEntity.avatarPictureIsSilhouette)
        attributeAvatarPictureIsSilhouette.attributeType = .booleanAttributeType
        attributeAvatarPictureIsSilhouette.isOptional = false
        attributeAvatarPictureIsSilhouette.defaultValue = true

        let attributeAvatarPictureData = NSAttributeDescription()
        attributeAvatarPictureData.name = #keyPath(FriendEntity.avatarPictureData)
        attributeAvatarPictureData.attributeType = .binaryDataAttributeType
        attributeAvatarPictureData.isOptional = true
        attributeAvatarPictureData.allowsExternalBinaryDataStorage = true

        let indexDescription = NSFetchIndexElementDescription(property: attributeUserName, collationType: .binary)
        indexDescription.isAscending = true
        let index = NSFetchIndexDescription(name: "com_mc_index_friend_userName", elements: [indexDescription])

        let entity = NSEntityDescription()
        entity.name = FriendEntity.entityName
        entity.managedObjectClassName = FriendEntity.entityClassName
        entity.properties = [attributeUserName, attributeAvatarPictureURL,
                                    attributeAvatarPictureIsSilhouette, attributeAvatarPictureData]
        entity.renamingIdentifier = "com.mc.entity-friend"
        entity.indexes = [index]

        return entity
    }

    private func makeProfileEntity() -> NSEntityDescription {

        let attributeUserName = NSAttributeDescription()
        attributeUserName.name = #keyPath(ProfileEntity.userName)
        attributeUserName.attributeType = .stringAttributeType
        attributeUserName.isOptional = false

        let attributeHomeTown = NSAttributeDescription()
        attributeHomeTown.name = #keyPath(ProfileEntity.homeTown)
        attributeHomeTown.attributeType = .stringAttributeType
        attributeHomeTown.isOptional = true

        let attributeCoverPhotoData = NSAttributeDescription()
        attributeCoverPhotoData.name = #keyPath(ProfileEntity.coverPhotoData)
        attributeCoverPhotoData.attributeType = .binaryDataAttributeType
        attributeCoverPhotoData.isOptional = true
        attributeCoverPhotoData.allowsExternalBinaryDataStorage = true

        let attributeAvatarPictureData = NSAttributeDescription()
        attributeAvatarPictureData.name = #keyPath(ProfileEntity.avatarPictureData)
        attributeAvatarPictureData.attributeType = .binaryDataAttributeType
        attributeAvatarPictureData.isOptional = true
        attributeAvatarPictureData.allowsExternalBinaryDataStorage = true

        let indexDescription = NSFetchIndexElementDescription(property: attributeUserName, collationType: .binary)
        indexDescription.isAscending = true
        let index = NSFetchIndexDescription(name: "com_mc_index_profile_userName", elements: [indexDescription])

        let entity = NSEntityDescription()
        entity.name = ProfileEntity.entityName
        entity.managedObjectClassName = ProfileEntity.entityClassName
        entity.properties = [attributeUserName, attributeHomeTown, attributeCoverPhotoData, attributeAvatarPictureData]
        entity.renamingIdentifier = "com.mc.entity-profile"
        entity.indexes = [index]

        return entity
    }

    private func makePostEntity() -> NSEntityDescription {

        let attributeCreatedDate = NSAttributeDescription()
        attributeCreatedDate.name = #keyPath(PostEntity.createdDate)
        attributeCreatedDate.attributeType = .dateAttributeType
        attributeCreatedDate.isOptional = false

        let attributeDescription = NSAttributeDescription()
        attributeDescription.name = #keyPath(PostEntity.desc)
        attributeDescription.attributeType = .stringAttributeType
        attributeDescription.isOptional = true

        let attributeID = NSAttributeDescription()
        attributeID.name = #keyPath(PostEntity.id)
        attributeID.attributeType = .stringAttributeType
        attributeID.isOptional = false

        let attributeType = NSAttributeDescription()
        attributeType.name = #keyPath(PostEntity.type)
        attributeType.attributeType = .stringAttributeType
        attributeType.isOptional = false

        let attributeTitle = NSAttributeDescription()
        attributeTitle.name = #keyPath(PostEntity.title)
        attributeTitle.attributeType = .stringAttributeType
        attributeTitle.isOptional = true

        let attributeSubtitle = NSAttributeDescription()
        attributeSubtitle.name = #keyPath(PostEntity.subtitle)
        attributeSubtitle.attributeType = .stringAttributeType
        attributeSubtitle.isOptional = true

        let attributePictureData = NSAttributeDescription()
        attributePictureData.name = #keyPath(PostEntity.pictureData)
        attributePictureData.attributeType = .binaryDataAttributeType
        attributePictureData.isOptional = true
        attributePictureData.allowsExternalBinaryDataStorage = true

        let attributePictureURL = NSAttributeDescription()
        attributePictureURL.name = #keyPath(PostEntity.pictureURL)
        attributePictureURL.attributeType = .URIAttributeType
        attributePictureURL.isOptional = true

        let attributeVideoURL = NSAttributeDescription()
        attributeVideoURL.name = #keyPath(PostEntity.videoURL)
        attributeVideoURL.attributeType = .URIAttributeType
        attributeVideoURL.isOptional = true

        let indexDescription1 = NSFetchIndexElementDescription(property: attributeCreatedDate, collationType: .binary)
        indexDescription1.isAscending = true
        let index1 = NSFetchIndexDescription(name: "com_mc_index_post_createdDate", elements: [indexDescription1])

        let indexDescription2 = NSFetchIndexElementDescription(property: attributeID, collationType: .binary)
        indexDescription2.isAscending = true
        let index2 = NSFetchIndexDescription(name: "com_mc_index_post_id", elements: [indexDescription2])

        let entity = NSEntityDescription()
        entity.name = PostEntity.entityName
        entity.managedObjectClassName = PostEntity.entityClassName
        entity.properties = [attributeCreatedDate, attributeDescription, attributeID, attributeVideoURL,
                                    attributePictureData, attributePictureURL, attributeType, attributeTitle, attributeSubtitle]
        entity.renamingIdentifier = "com.mc.entity-post"
        entity.indexes = [index1, index2]

        return entity
    }

}

更新2:

似乎从代码创建NSManagedObjectModel的正确方法 - 创建没有子类化。

public class ManagedObjectModel {

    public static func makeModel() -> NSManagedObjectModel {
        let model = NSManagedObjectModel() // No need to make subclass. Just assign `entities` property.
        model.entities = [makeFriendEntity(),
                          makeProfileEntity(),
                          makePostEntity()]
        return model
    }

    ...
}

0 个答案:

没有答案