GBA002/Delta/Database/Model/Human/Game.swift
Riley Testut 5c6c66c9a1 Fixes crashes when loading Game or SaveState that had been overwritten by a duplicate entry
When Core Data detects a duplicate entry, it deletes the previous entry. This caused Delta to delete the associated ROM and Save State files. Now, there is a check in prepareForDeletion to make sure the object being deleted is not simply being replaced by a newer entry during a merge.
2016-12-26 15:56:33 -06:00

69 lines
2.1 KiB
Swift

//
// Game.swift
// Delta
//
// Created by Riley Testut on 10/3/15.
// Copyright © 2015 Riley Testut. All rights reserved.
//
import Foundation
import DeltaCore
@objc(Game)
public class Game: _Game, GameProtocol
{
public var fileURL: URL {
var fileURL: URL!
self.managedObjectContext?.performAndWait {
fileURL = DatabaseManager.gamesDirectoryURL.appendingPathComponent(self.filename)
}
return fileURL
}
}
extension Game
{
override public func prepareForDeletion()
{
super.prepareForDeletion()
guard let managedObjectContext = self.managedObjectContext else { return }
// If a game with the same identifier is also currently being inserted, Core Data is more than likely resolving a conflict by deleting the previous instance
// In this case, we make sure we DON'T delete the game file + misc other Core Data relationships, or else we'll just lose all that data
guard !managedObjectContext.insertedObjects.contains(where: { ($0 as? Game)?.identifier == self.identifier }) else { return }
guard FileManager.default.fileExists(atPath: self.fileURL.path) else { return }
do
{
try FileManager.default.removeItem(at: self.fileURL)
}
catch
{
print(error)
}
for collection in self.gameCollections where collection.games.count == 1
{
// Once this game is deleted, collection will have 0 games, so we should delete it
managedObjectContext.delete(collection)
}
// Manually cascade deletion since SaveState.fileURL references Game, and so we need to ensure we delete SaveState's before Game
// Otherwise, we crash when accessing SaveState.game since it is nil
for saveState in self.saveStates
{
managedObjectContext.delete(saveState)
}
if managedObjectContext.hasChanges
{
managedObjectContext.saveWithErrorLogging()
}
}
}