Reputation: 1484
I have a model which looks like this and contains NSManagedObject properties, namely the blendsWith
property which is a type of [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
looks like this:
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 {
}
}
When I go to fetch the Oil
data stored locally, I get this crash:
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'
What could be causing this crash?
For reference, my fetching method looks like this:
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]()
}
}
And works like this:
let arrat : [Oil] = CoreDataHelper.sharedInstance.getItems()
Upvotes: 0
Views: 615
Reputation: 5358
A Transformable
is usually coded by CoreData to Data
(stored just as that), and coding an NSManagedObject
may do things you do not expect. Decoding it could make things „more“ unexpected. (Coding done by NSKeyedArchiver
and NSKeyedUnarchiver
automatically on assignment/use.)
If you want to use Transformable
then making it an NSManagedObject
is pointless due to the argument above. (I at least have no experience with it, and have not heard what use it would have.)
So its usually Transformable
OR CoreData-relationships
(with NSManagedObject
s) to model one relationship in CoreData, but not both to model a single one.
Upvotes: 0
Reputation: 12018
If you debug this code does it ever step into the Tag init
function? It appears the compiler is not seeing your Tag.init function which is most likely due to your Data Model for the Oil object not correctly setting the class type of the blendsWith
property.
Check your data model for Oil and make sure that blendsWith
is set to the correct type of Tag.
EDIT:
For Core Data to pick up your class setting you might need to add the objc
flag before your class definition:
@objc(Tag)
public class Tag ...
Upvotes: 0