Core Data: Beyond the Basics

Jul 26 2022 Swift 5.5, iOS 15, Xcode 13.3.1

Part 2: Advanced Core Data

15. Saving Launches with Batch Operations

Lesson Complete

Play Next Lesson
Next
Save for later
About this episode

See forum comments
Cinema mode Mark as Complete Download course materials
Previous episode: 14. Asynchronously Loading Launches Next episode: 16. Saving Launches Concurrently

This video was last updated on Jul 26 2022

Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.

You can unlock the rest of this video course, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.

Now that you have data from the SpaceX API, it’s time to put that data in the database. There are two techniques you’ll use together to do this: one is batch operations, which you’ll learn about in this episode, and asynchronous Core Data, which you’ll learn about in the next episode.

private func createBatchInsertLaunchRequest(from launchCollection: [SpaceXLaunchJSON]) -> NSBatchInsertRequest {

}
var index = 0
let total = launchCollection.count
let batchInsertRequest = NSBatchInsertRequest(entity:  
  SpaceXLaunch.entity(), dictionaryHandler: { dictionary in
  guard index < total else { return true }
  dictionary.addEntries(from: launchCollection[index].dictionaryValue as [AnyHashable: Any])
    index += 1
    return false
  })
return batchInsertRequest
var dictionaryValue: [String: Any] {
	[
	  "reused": reused as Any,
	  "recoveryAttempt": recoveryAttempt as Any,
	  "recovered": recovered as Any,
	  "ships": ships,
	  "id": id
	]
}
protocol BatchInsertable: Codable {
  var dictionaryValue: [String: Any] { get }
}
let taskContext = container.viewContext
let fairings = launchCollection.map { ($0.id, $0.fairings) }
let links = launchCollection.map { ($0.id, $0.links) }
var list: SpaceXLaunchList!
let fetchRequest = SpaceXLaunchList.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "title == %@", listName)
let results = try taskContext.fetch(fetchRequest)
if let fetchedList = results.first {
	list = fetchedList
}
let batchInsertRequest = createBatchInsertLaunchRequest(from: launchCollection)
if let fetchResult = try?
  taskContext.execute(batchInsertRequest),
  let batchInsertResult = fetchResult as? NSBatchInsertResult,
  let success = batchInsertResult.result as? Bool, 
  success {
	  return
	} else {
		throw LaunchError.batchInsertError
	}
private func createBatchInsertRelationshipRequest<T: BatchInsertable, E: NSManagedObject>(from relationshipCollection: [(String, T?)], for type: E.Type) -> NSBatchInsertRequest {
	var index = 0
	let total = relationshipCollection.count
	
	// Provide one dictionary at a time when the closure is called.
	let batchInsertRequest = NSBatchInsertRequest(entity: E.entity(), dictionaryHandler: { dictionary in
	  guard index < total else { return true }
	  guard let value = relationshipCollection[index].1 else { index += 1; return false }
	  dictionary.addEntries(from: value.dictionaryValue as [AnyHashable: Any])
	  index += 1
	  return false
	})
	
	return batchInsertRequest
}
let batchInsertRequest2 = createBatchInsertRelationshipRequest(from: fairings, for: SpaceXFairings.self)
if let fetchResult = try? taskContext.execute(batchInsertRequest2),
let batchInsertResult = fetchResult as? NSBatchInsertResult,
let success = batchInsertResult.result as? Bool, success {
  return
} else {
throw LaunchError.batchInsertError
}
// Setup the fairing relationships
for (id, fairing) in fairings {
	guard let fairing = fairing else { continue }
	let fairingFetchRequest = SpaceXFairings.fetchRequest()
	fairingFetchRequest.predicate = NSPredicate(format: "id == %@", argumentArray: [fairing.id])
	
	let launchFetchRequest = SpaceXLaunch.fetchRequest()
	launchFetchRequest.predicate = NSPredicate(format: "id == %@", argumentArray: [id])
	
	let returnedFairing = try taskContext.fetch(fairingFetchRequest) as [SpaceXFairings]
	let launch = try taskContext.fetch(launchFetchRequest) as [SpaceXLaunch]
	guard !returnedFairing.isEmpty, !launch.isEmpty else { continue }
	let matchedFairing = returnedFairing[0]
	let matchedLaunch = launch[0]
	matchedFairing.launch = matchedLaunch
}
try taskContext.save()
// Use a batch insert request to add the links
let batchInsertRequest3 = createBatchInsertRelationshipRequest(from: links, for: SpaceXLinks.self)
if let fetchResult = try? taskContext.execute(batchInsertRequest3),
let batchInsertResult = fetchResult as? NSBatchInsertResult,
let success = batchInsertResult.result as? Bool, success {
  return
} else {
	throw LaunchError.batchInsertError
}

// Setup the link relationships
for (id, links) in links {
	let linksFetchRequest = SpaceXLinks.fetchRequest()
	linksFetchRequest.predicate = NSPredicate(format: "id == %@", argumentArray: [links.id])
	
	let launchFetchRequest = SpaceXLaunch.fetchRequest()
	launchFetchRequest.predicate = NSPredicate(format: "id == %@", argumentArray: [id])
	
	let returnedLinks = try taskContext.fetch(linksFetchRequest) as [SpaceXLinks]
	let launch = try taskContext.fetch(launchFetchRequest) as [SpaceXLaunch]
	guard !returnedLinks.isEmpty, !launch.isEmpty else { continue }
	returnedLinks[0].launch = launch[0]
	launch[0].addToSpaceXList(list)
}
try taskContext.save()