在CoreData中获取实体会导致崩溃

时间:2018-08-29 19:38:27

标签: ios swift core-data nsfetchrequest

我有一个看起来像这样的模型,其中包含NSManagedObject属性,即blendsWith属性,它是[Tag]的一种类型:

extension Oil {

@nonobjc public class func fetchRequest() -> NSFetchRequest<Oil> {
    return NSFetchRequest<Oil>(entityName: "Oil")
}

@NSManaged public var blendsWith: [Tag]?
@NSManaged public var color: String?
@NSManaged public var commentsCount: Int64
@NSManaged public var id: Int64
@NSManaged public var imageURL: String?
@NSManaged public var latinName: String?
@NSManaged public var name: String?
@NSManaged public var properties: NSObject?
@NSManaged public var research: String?
@NSManaged public var resourceType: String?
@NSManaged public var viewsCount: Int64

}

public class Oil: NSManagedObject, Codable {

enum CodingKeys: String, CodingKey {
    case resourceType = "resource_type"
    case id, name
    case imageURL = "image_url"
    case color
    case latinName = "latin_name"
    case emotions
    case safetyInformation = "safety_information"
    case fact, research
    case viewsCount = "views_count"
    case commentsCount = "comments_count"
    case blendsWith = "blends_with"
    case foundInBlends = "found_in_blends"
    case properties
    case sourcingMethods = "sourcing_methods"
    case usages
}

required convenience public init(from decoder: Decoder) throws {
    let context = CoreDataHelper.sharedInstance.persistentContainer.viewContext
    guard let entity = NSEntityDescription.entity(forEntityName: "Oil", in: context) else { fatalError() }

    self.init(entity: entity, insertInto: context)

    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.resourceType = try! container.decodeIfPresent(String.self, forKey: .resourceType)!
    self.id = try! container.decodeIfPresent(Int64.self, forKey: .id)!
    self.name = try! container.decodeIfPresent(String.self, forKey: .name)!
    self.imageURL = try! container.decodeIfPresent(String.self, forKey: .imageURL)!
    self.color = try! container.decodeIfPresent(String.self, forKey: .color)!
    self.viewsCount = try! container.decodeIfPresent(Int64.self, forKey: .viewsCount)!
    self.viewsCount = try! container.decodeIfPresent(Int64.self, forKey: .viewsCount)!
    self.commentsCount = try! container.decodeIfPresent(Int64.self, forKey: .commentsCount)!
    self.latinName = try! container.decodeIfPresent(String.self, forKey: .latinName)!

    if let blendsWith = try container.decodeIfPresent([Tag].self, forKey: CodingKeys.blendsWith) {
        self.blendsWith = blendsWith
    }
}

public func encode(to encoder: Encoder) throws {

}

}

Tag看起来像这样:

extension Tag {

@nonobjc public class func fetchRequest() -> NSFetchRequest<Tag> {
    return NSFetchRequest<Tag>(entityName: "Tag")
}

@NSManaged public var id: Int64
@NSManaged public var name: String?
@NSManaged public var resourceType: String?
@NSManaged public var tagType: String?
@NSManaged public var viewsCount: Int64

}

public class Tag: NSManagedObject, Codable {

enum CodingKeys: String, CodingKey {
    case resourceType = "resource_type"
    case id, name
    case viewsCount = "views_count"
    case tagType = "tag_type"
}

required convenience public init(from decoder: Decoder) throws {
    let context = CoreDataHelper.sharedInstance.persistentContainer.viewContext
    guard let entity = NSEntityDescription.entity(forEntityName: "Tag", in: context) else { fatalError() }

    self.init(entity: entity, insertInto: context)

    let container = try decoder.container(keyedBy: CodingKeys.self)

    self.resourceType = try! container.decodeIfPresent(String.self, forKey: .resourceType)!
    self.id = try! container.decodeIfPresent(Int64.self, forKey: .id)!
    self.name = try! container.decodeIfPresent(String.self, forKey: .name)!
    if let viewsCount = try container.decodeIfPresent(Int64.self, forKey: .viewsCount) {
        self.viewsCount = viewsCount
    } else  {
        self.viewsCount = 0
    }
    if let tagType = try container.decodeIfPresent(String.self, forKey: .tagType) {
        self.tagType = tagType
    } else {
        self.tagType = "lol"
    }
}

public func encode(to encoder: Encoder) throws {

}

}

当我去获取本地存储的Oil数据时,发生此崩溃:

2018-08-29 20:31:30.602764+0100 EL[27994:14799374] -[EL.Tag initWithCoder:]: unrecognized selector sent to instance 0x60c000679980
2018-08-29 20:31:30.603905+0100 EL[27994:14799374] [error] error: exception handling request: <NSSQLFetchRequestContext: 0x608000181ee0> , -[EL.Tag initWithCoder:]: unrecognized selector sent to instance 0x60c000679980 with userInfo of (null)
CoreData: error: exception handling request: <NSSQLFetchRequestContext: 0x608000181ee0> , -[EL.Tag initWithCoder:]: unrecognized selector sent to instance 0x60c000679980 with userInfo of (null)
2018-08-29 20:31:30.612185+0100 EL[27994:14799374] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[EL initWithCoder:]: unrecognized selector sent to instance 0x60c000679980'

是什么原因导致此崩溃?

作为参考,我的提取方法如下:

func getItems<T : NSManagedObject>(predicate : NSPredicate? = nil) -> [T]{
        do {
            let reqest = T.fetchRequest()
            reqest.predicate = predicate
            if let items = try persistentContainer.viewContext.fetch(reqest) as? [T] {
                return items
            } else {
                return [T]()
            }
        } catch let error as NSError {
            print("Could not fetch. \(error), \(error.userInfo)")
            return [T]()
        }
    }

并且是这样的:

let arrat : [Oil] = CoreDataHelper.sharedInstance.getItems()

2 个答案:

答案 0 :(得分:0)

如果调试此代码,它是否曾经进入Tag init函数?看来编译器没有看到您的Tag.init函数,这很可能是由于Oil对象的数据模型未正确设置blendsWith属性的类类型。

检查数据模型是否为Oil,并确保将blendsWith设置为正确的代码类型。

编辑: 为了让Core Data获得您的班级设置,您可能需要在班级定义之前添加objc标志:

@objc(Tag)
public class Tag ...

答案 1 :(得分:0)

Core Data通常将Transformable编码为Data(照此存储),对NSManagedObject进行编码可能会做您不希望的事情。对其进行解码可能使事情“更多”变得出乎意料。 (由NSKeyedArchiverNSKeyedUnarchiver在分配/使用时自动进行编码。)

如果您想使用Transformable,则由于上面的论点,使其成为NSManagedObject是没有意义的。 (我至少没有经验,也没有听说过会有什么用。)

因此,通常使用TransformableCoreData-relationships(带有NSManagedObject)来模拟CoreData中的一个关系,但不能同时使用两者来模拟单个关系。