Casting JSON list of objects for NSBatchInsertRequest to [[String:Any]] fails

489 Views Asked by At

I have a small project at Github which downloads a JSON list of objects, parses it and stores in Core Data:

screenshot

In the view model I just iterate through the JSON list, create Core Data entities and then save the context:

URLSession.shared.dataTaskPublisher(for: url)
    .tryMap(handleOutput)
    .decode(type: TopResponse.self, decoder: JSONDecoder())
    .sink { completion in
        print("fetchTopModels completion=\(completion)")
    } receiveValue: { fetchedTops in
        PersistenceController.shared.container.performBackgroundTask { backgroundContext in
            backgroundContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
            backgroundContext.automaticallyMergesChangesFromParent = true
            backgroundContext.perform {
                for topModel in fetchedTops.data {
                    let topEntity = TopEntity(context: backgroundContext)
                    topEntity.language = language
                    topEntity.uid = Int32(topModel.id)
                    // etc.
                }
                if (backgroundContext.hasChanges) {
                    do {
                        try backgroundContext.save()

This works well, but is very slow when I have a list with 100000 objects.

So I have decided to create another small project at Github, which uses NSBatchInsertRequest.

And being a Swift newbie I already fail at the very first step :-)

I was thinking of casting the TopResponse.data to [[String:Any]]

struct TopResponse: Codable {
    let data: [TopModel]
}

struct TopModel: Codable, Identifiable {
    var id: Int { uid }
    let uid: Int
    // etc.
}

So in the new view model I have tried the code:

URLSession.shared.dataTaskPublisher(for: url)
    .tryMap(handleOutput)
    .decode(type: TopResponse.self, decoder: JSONDecoder())
    .sink { completion in
        print("fetchTopModels completion=\(completion)")
    } receiveValue: { topResponse in
        guard let fetchedTops = topResponse.data as? [[String: Any]] else { return }
        PersistenceController.shared.container.performBackgroundTask { backgroundContext in
            backgroundContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
            backgroundContext.automaticallyMergesChangesFromParent = true
            backgroundContext.perform {
                
                let batchInsert = NSBatchInsertRequest(entity: TopEntity.entity(), objects: fetchedTops)

                do {
                    try backgroundContext.execute(batchInsert)

but the casting fails and I see in debugger that fetchedTops has zero elements:

Xcode screenshot

Why is it happening? I was expecting the JSON list of objects to be casted perfectly to a [[String:Any]]

0

There are 0 best solutions below