EVReflection with NSManagedObject Crashes / not Working - ios

hI: I've been using EVReflection to make our Network Layer Fully Restful and I Must say: AWESOME WORK! Thanks to #evermeer for this Library. you can get it here: https://github.com/evermeer/EVReflection
Now, to the Issue:
The Next Step is to get those Objects Straight into CORE DATA. Here is one of the Classes in Question
// Here is the Object With the EVReflectable Extension as the Documentation Claims:
import Foundation
import CoreData
import EVReflection
public class NGTripSummary: NSManagedObject { }
extension NGTripSummary: EVReflectable { }
// and HERE are the Object Properties:
// NGTripSummary+CoreDataProperties.swift
import Foundation
import CoreData
extension NGTripSummary {
#nonobjc public class func fetchRequest() -> NSFetchRequest<NGTripSummary> {
return NSFetchRequest<NGTripSummary>(entityName: "NGTripSummary")
}
#NSManaged public var carId: Int64
#NSManaged public var citiesVisited: NSObject?
#NSManaged public var cost: Double
#NSManaged public var distance: Double
#NSManaged public var globalStartDate: NSDate?
#NSManaged public var globalEndDate: NSDate?
#NSManaged public var kpl: Double
#NSManaged public var litres: Double
#NSManaged public var routeLocations: NSObject?
#NSManaged public var sessionId: Int64
#NSManaged public var localStartDate: NSDate?
#NSManaged public var localEndDate: NSDate?
#NSManaged public var duration: Int64
#NSManaged public var speed: Double
#NSManaged public var _id: Int64
#NSManaged public var sessionUuid: String?
#NSManaged public var tripUuid: String?
}
// . here is the JSON String that Represents a Demo Object:
let tripData = "{\"id\":26105240,\"userId\":25796277,\"carId\":25817551,\"vehicleId\":57812351,\"sessionUuid\":\"53324259-aa69-41c8-8f9e-c62bdb70f165\",\"tripUuid\":\"afdd8f55-6d14-4cf9-bd9f-5b6da47aaf93\",\"localStartDate\":1487170622490,\"localEndDate\":1487178323654,\"globalStartDate\":1487163422490,\"globalEndDate\":1487171123654,\"routeLocations\":null,\"litres\":24.7699,\"kpl\":0.0772,\"cost\":153.3258,\"distance\":1.9132,\"duration\":491.958,\"speed\":14.0}"
// and HERE is the Method I'm Trying to use to Create this Mock Object:
func makeMockData() {
let singleTrip = NGTripSummary(json: tripData)
print("Single Trip: \(singleTrip)")
}
// NOW: When Creating the Object, the Crash Happens HERE # class EVReflection:
// Call your own object validators that comply to the format: validate<Key>:Error:
do {
var setValue: AnyObject? = value as AnyObject?
/* LINE 923: CRASH HAPPENS HERE -> */ try anyObject.validateValue(&setValue, forKey: key)
anyObject.setValue(setValue, forKey: key)
} catch _ {
(anyObject as? EVReflectable)?.addStatusMessage(.InvalidValue, message: "Not a valid value for object `\(NSStringFromClass(type(of: (anyObject as AnyObject))))`, type `\(type)`, key `\(key)`, value `\(value)`")
print("INFO: Not a valid value for object `\(NSStringFromClass(type(of: (anyObject as AnyObject))))`, type `\(type)`, key `\(key)`, value `\(value)`")
}
////////////////// REASON FOR CRASH ////////////////////
[error] error: CoreData: error: Failed to call designated initializer on NSManagedObject class 'NGTripSummary'
CoreData: error: CoreData: error: Failed to call designated initializer on NSManagedObject class 'NGTripSummary'
//////////////////////////////////////////////////
-> Anybody, PLEASE HELP :-0

The error message describes the exact problem. You appear to be creating instances of NGTripSummary with this line of code:
let singleTrip = NGTripSummary(json: tripData)
But NGTripSummary is a subclass of NSManagedObject, and you're never calling the designated initializer for NSManagedObject. That's required. You must call init(entity:insertInto:) on NSManagedObject, or else use the factory method insertNewObject(forEntityName:into:) on NSEntityDescription to get a valid managed object. If you don't, you get this specific error and your app crashes.
If you need to create instances using tripData, you can do that, but you also need to provide a managed object context and an entity description. You could do that with a convenience initializer on your class, which would call the designated initializer as part of the initialization process.

EVReflection now has a Cocoapods subspec for CoreData. For more information see https://github.com/evermeer/EVReflection/tree/master/Source/CoreData
It will let you write code like this:\
let moc: NSManagedObjectContext = EVReflectionTestsData().moc // Your code for getting the NSManagedObjectContext.
let obj = CoreDataPerson(context: moc, json: "{\"firstName\" : \"Edwin\", \"lastName\" : \"Vermeer\"}")
try! moc.save() //TODO: implement error handling

Related

How to handle optional/missing attributes of related Core Data objects in NDPredicate

I've recently ran into an issue with core data that I'm unable to solve.
I have the following object and relationships Recommendation <---> Item
extension Recommendation {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Recommendation> {
return NSFetchRequest<Recommendation>(entityName: "Recommendation")
}
#NSManaged public var age: Int?
#NSManaged public var tags: Array<String>?
#NSManaged public var object: Item?
}
extension Item {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Item> {
return NSFetchRequest<Recommendation>(entityName: "Item")
}
#NSManaged public var id: String?
#NSManaged public var name: String?
#NSManaged public var recommendation: Recommendation?
}
I want to fetch all Items based on attributes in their related Recommendation.
Some of these attributes could be missing.
How would I create a NSPredicate to fetch objects where the Recommendation.age or Recommendation.tags could be non-existent (applicable to all ages/tags) or should be compared against a provided value?
Should I always provide a Default Value?

How to elegant use CoreData with Swift3 + Optional + NSOrderedSet + Generic

When using Core Data with Swift&Xcode8, i generate a model below, but i feel it's really hard to use :
The chapter relation to another model, and it's type was generated to NSOrderedSet
I actually can't use generic with NSOrderedSet such as NSOrderedSet<Chapter>?
I have to modify the collection with the generated accessors, it's annoying
all the attribute generated by Core Data is optional, with the model nested deep, i have to use a lot of guard or ? to unpack optional value
And i doubt that how you guys play with Core Data together with Swift ...
:(
Should i try using Realm instead ?
CourseDetail.swift :
extension CourseDetail {
#NSManaged public var title: String?
#NSManaged public var chapter: NSOrderedSet?
#NSManaged public var author: NSOrderedSet?
}
// MARK: Generated accessors for chapter
extension CourseDetail {
#objc(addChapterObject:)
#NSManaged public func addToChapter(_ value: Chapter)
#objc(removeChapterObject:)
#NSManaged public func removeFromChapter(_ value: Chapter)
#objc(addChapter:)
#NSManaged public func addToChapter(_ values: NSSet)
#objc(removeChapter:)
#NSManaged public func removeFromChapter(_ values: NSSet)
}
In my case I don't use the generated class, I write them myself without using optionals except where needed. You don't have to use the generated classes.
Even the generated accessors can be hand written, they follow a simple Key-Value Coding naming convention.
If I were writing the class it would look something like:
#objc(CourseDetail)
public final class CourseDetail: NSManagedObject { // The actual class, no longer an extension.
#NSManaged public var title: String
#NSManaged public var chapter: NSSet
#NSManaged public var author: NSSet
// A convenience for fetch requests
#nonobjc public class func fetchRequest() -> NSFetchRequest<CourseDetail> {
return NSFetchRequest<CourseDetail>(entityName: "CourseDetail");
}
#objc(addChapterObject:)
#NSManaged public func addToChapter(_ value: Chapter)
#objc(removeChapterObject:)
#NSManaged public func removeFromChapter(_ value: Chapter)
#objc(addChapter:)
#NSManaged public func addToChapter(_ values: NSSet)
#objc(removeChapter:)
#NSManaged public func removeFromChapter(_ values: NSSet)
}

How to create an interface for a CoreData model (NSManagedObject)?

I'm trying to migrate from CoreData to FireBase. Hence the need for a shared interface across the app for my model.
I have a FTEvent class...
#objc(FTEvent)
public class FTEvent: FTEventBase {
}
that inherits from FTEventBase
#objc(FTEventBase)
public class FTEventBase: NSManagedObject {
}
Now I have a new class called FTRecord, which should share an interface with FTEvent above.
class FTRecord {
let key: String
var notes: String
var rating: Int
var time: String
var timestamp: Double
}
This is now where the problem begins. I could obviously create a protocol as interface for both FTRecord and FTEvent.
protocol IEvent {
var is_deleted: Bool? { get set }
var notes: String? { get set }
var date: Date? { get set }
var timestamp: Double? { get set }
var rating: Int? { get set }
}
But this becomes very hard since Bool in CoreData is actually a NSNumber. The Date is NSDate. Because of these type differences, I have no way to create a common interface.
Is there any advice, how I could achieve that?

Parse+Swift, "-[Swift._NSContiguousString objectId]: unrecognized selector sent to instance" error

I'm using Parse and I had a PFObject I was using to represent a "Job". It worked fined, but it was tedious always using setObject:forKey: and objectForKey: rather than accessing properties.
So, I decided to make a "proper" PFObject subclass. Now, every call made to "objectId" gives the above unrecognized selector error -- even calls that have nothing to do with my subclass.
I created my subclass "by the book", as far as I can tell (below), and I do call Job.registerSubclass() before Parse.setApplicationId: in my AppDelegate. Anybody seen this problem?
import Foundation
import Parse
class Job: PFObject, PFSubclassing {
#NSManaged var categoryName: String
#NSManaged var categoryId: String
#NSManaged var state: String
#NSManaged var details: String?
#NSManaged var jobDescription: String
#NSManaged var location: String
#NSManaged var dates: [String]
#NSManaged var images: PFFile?
#NSManaged var questionSequence: [String]?
#NSManaged var consumerResponseIndices: [Int]?
#NSManaged var isPosted: Bool
#NSManaged var bids: [AnyObject]?
override class func initialize() {
struct Static {
static var onceToken : dispatch_once_t = 0;
}
dispatch_once(&Static.onceToken) {
self.registerSubclass()
}
}
class func parseClassName() -> String {
return "Job"
}
}
I got the same issue before.
You may have this error when trying to convert NSArray/NSDictionary to String type, so it turns to NSContiguousString type.
You can check:
dates
questionSequence
consumerResponseIndices
bids
to see if this happened.
In my case the problem was :
if let countryLocale = (notification.userInfo![Constants.CountryLocale]!.firstObject as? String { code }
and solved with
if let countryLocale = (notification.userInfo![Constants.CountryLocale] as! [AnyObject]).first as? String { code }

Appending PFObject to Array - EXC_BAD_ACCESS

I am currently using Swift and Parse and have run into an issue which I haven't been able resolve for the past several hours.
On a button click, I am attempting to add an Employee object to an Event object's eventAttendee's array.
#IBAction func joinEvent(sender: AnyObject) {
var employee = Employee.currentUser()
employee.events.append(event)
employee.saveInBackgroundWithBlock(nil)
event.eventAttendees.append(employee)
event.saveInBackgroundWithBlock(nil)
}
The event is added to the employee events, but the employee is not added to the event attendees list. The function throws a EXC_BAD_ACCESS (code=1, address=0x0) on the append(employee) line, with no other error message.
My event class looks like this:
class VolunteerEvent : PFObject, PFSubclassing {
#NSManaged var eventName: String
#NSManaged var dateOfEvent: NSDate
#NSManaged var eventDescription: String
#NSManaged var eventURL: String?
#NSManaged var eventImage: PFFile
#NSManaged var contactEmail: String
#NSManaged var contactPhone: NSNumber
#NSManaged var eventOrganizer: Employee
#NSManaged var eventAttendees: [Employee]
class func parseClassName() -> String {
return "VolunteerEvent"
}
}
My Employee class extends PFUser, although when I print out the description of my employee I get that it is a PFUser. I can't tell if this is the issue. When I print out the event, it looks like I expect it to look. I also tried switching the eventAttendees to be an array of PFUser's instead of Employee's, but that didn't work either.
Any help would be much appreciated. Thank you.
I subclass my PFObjects this way,
class Person : PFObject, PFSubclassing {
var firstName: String {
get {
return objectForKey("firstName") as? String ?? ""
}
set {
setObject(newValue, forKey: "firstName")
}
}
}
This way if there is no string in the parse database, I don't get nil, i get an empty string.
You can do this with your array, in fact all your object properties.
If nothing is returned, then you will get an empty array of Employee, rather than a nil object - which will cause your crash when you try an append to it.
You need to initialize your array before adding to it. Try var eventAttendees: [Employee] = []

Resources