Fetching entities in CoreData causing a crash
Fetching entities in CoreData causing a crash
I have a model which looks like this and contains NSManagedObject properties, namely the blendsWith
property which is a type of [Tag]
:
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
looks like this:
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
When I go to fetch the Oil
data stored locally, I get this crash:
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'
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()
NSKeyedUnArchiver
No I am not. Should I be?
– spogebob92
Aug 29 at 20:01
No, you shouldn't.
NSKeyedUnArchiver
calls initWithCoder
which is a part of the error message.– vadian
Aug 29 at 20:03
NSKeyedUnArchiver
initWithCoder
Is
Oil.blendswith
an NSSet
, an NSOrderedSet
or Transformable([Tag])?– Fabian
Aug 29 at 21:08
Oil.blendswith
NSSet
NSOrderedSet
a Transformable([Tag])
– spogebob92
Aug 29 at 21:09
2 Answers
2
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.
init
blendsWith
Check your data model for Oil and make sure that blendsWith
is set to the correct type of Tag.
blendsWith
EDIT:
For Core Data to pick up your class setting you might need to add the objc
flag before your class definition:
objc
@objc(Tag)
public class Tag ...
It does hit the breakpoint within the
init
function– spogebob92
Aug 29 at 20:46
init
Can you verify that your data model sets the blendsWith array in the Oil entity with the correct Tag class?
– davidethell
Aug 29 at 20:51
Also check my edit about adding the
objc
flag before your class declaration.– davidethell
Aug 29 at 20:55
objc
Can confirm its correct and the Objc flag doesn't fix the problem. Thanks for the help though.
– spogebob92
Aug 29 at 21:10
When you confirmed it was hitting the breakpoint I didn't think the objc flag was going to help, but it was worth a shot. It does appear iOS is correctly seeing your class assignment.
– davidethell
Aug 29 at 21:55
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.)
Transformable
Data
NSManagedObject
NSKeyedArchiver
NSKeyedUnarchiver
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.)
Transformable
NSManagedObject
So its usually Transformable
OR CoreData-relationships
(with NSManagedObject
s) to model one relationship in CoreData, but not both to model a single one.
Transformable
CoreData-relationships
NSManagedObject
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Are you calling
NSKeyedUnArchiver
somewhere?– vadian
Aug 29 at 19:58