I have a small project at Github which downloads a JSON list of objects, parses it and stores in Core Data:
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:
Why is it happening? I was expecting the JSON list of objects to be casted perfectly to a [[String:Any]]

