NSBatchInsertRequest problem with decoding a simple Date

Hi,


I have backup functionality which takes the NSManaged Object and save them as JSON File.

The JSON looks like this :


[
  {
  "id": "58454F9D-08BC-4302-A5FC-11545EFB8C42",
  "created": 608479894.33327103,
  "name": "Freezer",
  "modified": 608479894.33327198
  },
  {
  "id": "3AB234DF-E16D-43BE-AA57-CA14E729EEA8",
  "created": 608479894.33316803,
  "name": "Fridge",
  "modified": 608479894.33318496
  },
  {
  "id": "6FA1E8D0-8629-413B-9C71-0377260ECFFF",
  "created": 608479894.33331501,
  "name": "Pantry",
  "modified": 608479894.33331501
  }
]


And the corresponding NSManagedObject class looks as Below :


@objc(Storage)
class Storage: NSManagedObject, Encodable {
    
    // MARK: - Properties

    @NSManaged public var id: String    
    @NSManaged public var name: String
    @NSManaged public var created: Date
    @NSManaged public var modified: Date
    
    // MARK: - Encodable
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(created, forKey: .created)
        try container.encode(modified, forKey: .modified)
        try container.encodeIfPresent(name, forKey: .name)
    }
}


As you can see it is a pretty simple NSManagedObject class, and both the JSON keys and the class attributes matches.


The problem is that by using the NSBatchInsertRequest to import the JSON file back to the database this fails in the Created Date field parsing, whith the following error :


Error Domain=NSCocoaErrorDomain Code=1550 "created is not valid." 
UserInfo={NSValidationErrorObject=<NSSQLiteConnection: 0x7f809c607a90>, 
NSLocalizedDescription=created is not valid., key=created, value=608485537.09696996, 
NSValidationErrorKey=created, NSValidationErrorValue=608485537.09696996}


Is there something I have missed, does NSBatchInsertRequest use it own Date parser different that the one defined by default On Swift JSON ?

Looking forward for your help.

Answered by andre07 in 423804022

You could also do plain insert or batch insert on your own to reduce your memory footprint.

Depends on your amount of data though.


Check out https://developer.apple.com/documentation/coredata/loading_and_displaying_a_large_data_feed

What does your NSBatchInsertRequest call look like when you try to insert your data?


NSBatchInsertRequest needs for the objects parameter [[String : Any]]


Looks like the value type for your created attribute is not a Date.

Please find below how my NSBatchInsertRequest looks like :


    if let backup = try? JSONSerialization.jsonObject(with: dataFile.read(), options: []) as? [String: Any] {
        do {
            if let categories = backup["categories"] as? [[String: Any]] {
                let _ = try managedContext.execute(NSBatchInsertRequest(entity: Category.entity(), objects: categories))
            }
                
            if let storages = backup["storages"] as? [[String: Any]] {
                let _ = try managedContext.execute(NSBatchInsertRequest(entity: Storage.entity(), objects: data: storages))
            }
        } catch {
            self.finish(with: RestoreError.parsingBackupFile)
        }
    }

Do I need to iterate over each [[String:Any]] and convert data to the correct type explicitly before preparing the NSBatchInsertRequest ?

"All objects are instances of

NSString
,
NSNumber
,
NSArray
,
NSDictionary
, or
NSNull"

See: https://developer.apple.com/documentation/foundation/jsonserialization


Looks to me like you have 2 options:

1) replace your key="created" dictionary items explicit to [String : Date] instead of [String : Any]

2) save the created as a number in the database and create a computed property which will transform that number to a date object

Accepted Answer

You could also do plain insert or batch insert on your own to reduce your memory footprint.

Depends on your amount of data though.


Check out https://developer.apple.com/documentation/coredata/loading_and_displaying_a_large_data_feed

Thank you ! Then I guess I'll go with options 2 replace date with a NSNumber.

NSBatchInsertRequest problem with decoding a simple Date
 
 
Q