The user of my app can import in the ranges of 10k audio files.
An AudioFile entity is unique as long as BOTH its name and file extension are unique.
During the import, the user can cancel the import using a cancel button or could kill the app from app switcher and since NSBatchInsertRequest saves directly to disk, bypassing memory, how do I revert the changes or remove the managed objects that were already saved to disk?
func importFiles(from urls: [URL]) async {
let importContext = DataController.shared.createNewBackgroundContext()
var objects: [[String: Any]] = []
for url in urls {
if url.startAccessingSecurityScopedResource() {
let metadata = getMetadata(url: url)
let audioFileName = url.deletingPathExtension().lastPathComponent
let fileExtension = url.pathExtension
let artist = metadata?.value(forKey: "artist") as? String ?? "Unknown Artist"
let album = metadata?.value(forKey: "album") as? String ?? "Unknown Album"
let genre = metadata?.value(forKey: "genre") as? String ?? "Unknown Genre"
let composer = metadata?.value(forKey: "composer") as? String ?? "Unknown Composer"
let year = metadata?.value(forKey: "year") as? String ?? "Unknown Release Year"
let importDate = Date()
let artwork = audioFileName + ".(fileExtension)"
let trackNumber = metadata?.value(forKey: "trackNumber") as? Int ?? -1
let properties: [String: Any] = [
"name": audioFileName,
"artist": artist,
"album": album,
"genre": genre,
"year": year,
"composer": composer,
"importDate": importDate,
"trackNumber": trackNumber,
"artwork": artwork,
"fileExtension": fileExtension,
"favourite": false
]
objects.append(properties)
}
url.stopAccessingSecurityScopedResource()
}
await importContext.perform {
let batchInsertRequest = NSBatchInsertRequest(entity: AudioFile.entity(), objects: objects)
if let fetchResult = try? importContext.execute(batchInsertRequest),
let batchInsertResult = fetchResult as? NSBatchInsertResult,
let success = batchInsertResult.result as? Bool, success {
return
}
}