Refactors DatabaseManager into NSPersistentStore subclass
This commit is contained in:
parent
0d562da309
commit
da7705aaff
@ -64,7 +64,7 @@ class GameCollectionViewDataSource: NSObject
|
|||||||
|
|
||||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: Game.Attributes.type.rawValue, ascending: true), NSSortDescriptor(key: Game.Attributes.name.rawValue, ascending: true)]
|
fetchRequest.sortDescriptors = [NSSortDescriptor(key: Game.Attributes.type.rawValue, ascending: true), NSSortDescriptor(key: Game.Attributes.name.rawValue, ascending: true)]
|
||||||
|
|
||||||
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.sharedManager.managedObjectContext, sectionNameKeyPath: Game.Attributes.type.rawValue, cacheName: nil)
|
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: Game.Attributes.type.rawValue, cacheName: nil)
|
||||||
self.fetchedResultsController.delegate = previousDelegate
|
self.fetchedResultsController.delegate = previousDelegate
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|||||||
@ -6,114 +6,54 @@
|
|||||||
// Copyright © 2015 Riley Testut. All rights reserved.
|
// Copyright © 2015 Riley Testut. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
import CoreData
|
import CoreData
|
||||||
|
|
||||||
// Workspace
|
// Workspace
|
||||||
import Roxas
|
|
||||||
import DeltaCore
|
import DeltaCore
|
||||||
|
|
||||||
// Pods
|
// Pods
|
||||||
import FileMD5Hash
|
import FileMD5Hash
|
||||||
|
|
||||||
class DatabaseManager
|
final class DatabaseManager: NSPersistentContainer
|
||||||
{
|
{
|
||||||
static let sharedManager = DatabaseManager()
|
static let shared = DatabaseManager()
|
||||||
|
|
||||||
let managedObjectContext: NSManagedObjectContext
|
|
||||||
|
|
||||||
private let privateManagedObjectContext: NSManagedObjectContext
|
|
||||||
private let validationManagedObjectContext: NSManagedObjectContext
|
|
||||||
|
|
||||||
// MARK: - Initialization -
|
|
||||||
/// Initialization
|
|
||||||
|
|
||||||
private init()
|
private init()
|
||||||
{
|
{
|
||||||
let modelURL = Bundle.main.url(forResource: "Model", withExtension: "momd")
|
guard
|
||||||
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL!)
|
let modelURL = Bundle(for: DatabaseManager.self).url(forResource: "Model", withExtension: "momd"),
|
||||||
let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel!)
|
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
|
||||||
|
else { fatalError("Core Data model cannot be found. Aborting.") }
|
||||||
|
|
||||||
self.privateManagedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
super.init(name: "Delta", managedObjectModel: managedObjectModel)
|
||||||
self.privateManagedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator
|
|
||||||
self.privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
|
||||||
|
|
||||||
self.managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
|
|
||||||
self.managedObjectContext.parent = self.privateManagedObjectContext
|
|
||||||
self.managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
|
||||||
|
|
||||||
self.validationManagedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
|
||||||
self.validationManagedObjectContext.parent = self.managedObjectContext
|
|
||||||
self.validationManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(DatabaseManager.managedObjectContextWillSave(_:)), name: NSNotification.Name.NSManagedObjectContextWillSave, object: nil)
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(DatabaseManager.managedObjectContextDidSave(_:)), name: NSNotification.Name.NSManagedObjectContextDidSave, object: nil)
|
|
||||||
|
|
||||||
|
self.viewContext.automaticallyMergesChangesFromParent = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func startWithCompletion(_ completionBlock: ((performingMigration: Bool) -> Void)?)
|
//MARK: - Importing -
|
||||||
|
/// Importing
|
||||||
|
extension DatabaseManager
|
||||||
|
{
|
||||||
|
func importGames(at urls: [URL], completion: (([String]) -> Void)?)
|
||||||
{
|
{
|
||||||
DispatchQueue.global(qos: .userInitiated).async {
|
self.performBackgroundTask { (context) in
|
||||||
|
|
||||||
let storeURL = DatabaseManager.databaseDirectoryURL.appendingPathComponent("Delta.sqlite")
|
|
||||||
|
|
||||||
let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
|
|
||||||
|
|
||||||
var performingMigration = false
|
|
||||||
|
|
||||||
if
|
|
||||||
let sourceMetadata = try? NSPersistentStoreCoordinator.metadataForPersistentStore(ofType: NSSQLiteStoreType, at: storeURL, options: options),
|
|
||||||
let managedObjectModel = self.privateManagedObjectContext.persistentStoreCoordinator?.managedObjectModel
|
|
||||||
{
|
|
||||||
performingMigration = !managedObjectModel.isConfiguration(withName: nil, compatibleWithStoreMetadata: sourceMetadata)
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
try self.privateManagedObjectContext.persistentStoreCoordinator?.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options)
|
|
||||||
}
|
|
||||||
catch let error as NSError
|
|
||||||
{
|
|
||||||
if error.code == NSMigrationMissingSourceModelError
|
|
||||||
{
|
|
||||||
print("Migration failed. Try deleting \(storeURL)")
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
print(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
abort()
|
|
||||||
}
|
|
||||||
|
|
||||||
if let completionBlock = completionBlock
|
|
||||||
{
|
|
||||||
completionBlock(performingMigration: performingMigration)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Importing -
|
|
||||||
/// Importing
|
|
||||||
|
|
||||||
func importGamesAtURLs(_ URLs: [URL], withCompletion completion: (([String]) -> Void)?)
|
|
||||||
{
|
|
||||||
let managedObjectContext = self.backgroundManagedObjectContext()
|
|
||||||
managedObjectContext.perform() {
|
|
||||||
|
|
||||||
var identifiers: [String] = []
|
var identifiers: [String] = []
|
||||||
|
|
||||||
for URL in URLs
|
for url in urls
|
||||||
{
|
{
|
||||||
let identifier = FileHash.sha1HashOfFile(atPath: URL.path) as String
|
let identifier = FileHash.sha1HashOfFile(atPath: url.path) as String
|
||||||
|
|
||||||
let filename = identifier + "." + URL.pathExtension
|
let filename = identifier + "." + url.pathExtension
|
||||||
|
|
||||||
let game = Game.insertIntoManagedObjectContext(managedObjectContext)
|
let game = Game.insertIntoManagedObjectContext(context)
|
||||||
game.name = URL.deletingPathExtension().lastPathComponent ?? NSLocalizedString("Game", comment: "")
|
game.name = url.deletingPathExtension().lastPathComponent ?? NSLocalizedString("Game", comment: "")
|
||||||
game.identifier = identifier
|
game.identifier = identifier
|
||||||
game.filename = filename
|
game.filename = filename
|
||||||
|
|
||||||
let gameCollection = GameCollection.gameSystemCollectionForPathExtension(URL.pathExtension, inManagedObjectContext: managedObjectContext)
|
let gameCollection = GameCollection.gameSystemCollectionForPathExtension(url.pathExtension, inManagedObjectContext: context)
|
||||||
game.type = GameType(rawValue: gameCollection.identifier)
|
game.type = GameType(rawValue: gameCollection.identifier)
|
||||||
game.gameCollections.insert(gameCollection)
|
game.gameCollections.insert(gameCollection)
|
||||||
|
|
||||||
@ -123,11 +63,11 @@ class DatabaseManager
|
|||||||
|
|
||||||
if FileManager.default.fileExists(atPath: destinationURL.path)
|
if FileManager.default.fileExists(atPath: destinationURL.path)
|
||||||
{
|
{
|
||||||
try FileManager.default.removeItem(at: URL)
|
try FileManager.default.removeItem(at: url)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try FileManager.default.moveItem(at: URL, to: destinationURL)
|
try FileManager.default.moveItem(at: url, to: destinationURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
identifiers.append(game.identifier)
|
identifiers.append(game.identifier)
|
||||||
@ -141,9 +81,9 @@ class DatabaseManager
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
try managedObjectContext.save()
|
try context.save()
|
||||||
}
|
}
|
||||||
catch let error as NSError
|
catch
|
||||||
{
|
{
|
||||||
print("Failed to save import context:", error)
|
print("Failed to save import context:", error)
|
||||||
|
|
||||||
@ -154,27 +94,16 @@ class DatabaseManager
|
|||||||
{
|
{
|
||||||
completion(identifiers)
|
completion(identifiers)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Background Contexts -
|
|
||||||
/// Background Contexts
|
|
||||||
|
|
||||||
func backgroundManagedObjectContext() -> NSManagedObjectContext
|
|
||||||
{
|
|
||||||
let managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
|
||||||
managedObjectContext.parent = self.validationManagedObjectContext
|
|
||||||
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
|
||||||
|
|
||||||
return managedObjectContext
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: - File URLs -
|
||||||
|
/// File URLs
|
||||||
extension DatabaseManager
|
extension DatabaseManager
|
||||||
{
|
{
|
||||||
class var databaseDirectoryURL: URL
|
override class func defaultDirectoryURL() -> URL
|
||||||
{
|
{
|
||||||
let documentsDirectoryURL: URL
|
let documentsDirectoryURL: URL
|
||||||
|
|
||||||
@ -188,23 +117,23 @@ extension DatabaseManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
let databaseDirectoryURL = documentsDirectoryURL.appendingPathComponent("Database")
|
let databaseDirectoryURL = documentsDirectoryURL.appendingPathComponent("Database")
|
||||||
self.createDirectoryAtURLIfNeeded(databaseDirectoryURL)
|
self.createDirectory(at: databaseDirectoryURL)
|
||||||
|
|
||||||
return databaseDirectoryURL
|
return databaseDirectoryURL
|
||||||
}
|
}
|
||||||
|
|
||||||
class var gamesDirectoryURL: URL
|
class var gamesDirectoryURL: URL
|
||||||
{
|
{
|
||||||
let gamesDirectoryURL = DatabaseManager.databaseDirectoryURL.appendingPathComponent("Games")
|
let gamesDirectoryURL = DatabaseManager.defaultDirectoryURL().appendingPathComponent("Games")
|
||||||
self.createDirectoryAtURLIfNeeded(gamesDirectoryURL)
|
self.createDirectory(at: gamesDirectoryURL)
|
||||||
|
|
||||||
return gamesDirectoryURL
|
return gamesDirectoryURL
|
||||||
}
|
}
|
||||||
|
|
||||||
class var saveStatesDirectoryURL: URL
|
class var saveStatesDirectoryURL: URL
|
||||||
{
|
{
|
||||||
let saveStatesDirectoryURL = DatabaseManager.databaseDirectoryURL.appendingPathComponent("Save States")
|
let saveStatesDirectoryURL = DatabaseManager.defaultDirectoryURL().appendingPathComponent("Save States")
|
||||||
self.createDirectoryAtURLIfNeeded(saveStatesDirectoryURL)
|
self.createDirectory(at: saveStatesDirectoryURL)
|
||||||
|
|
||||||
return saveStatesDirectoryURL
|
return saveStatesDirectoryURL
|
||||||
}
|
}
|
||||||
@ -212,141 +141,20 @@ extension DatabaseManager
|
|||||||
class func saveStatesDirectoryURLForGame(_ game: Game) -> URL
|
class func saveStatesDirectoryURLForGame(_ game: Game) -> URL
|
||||||
{
|
{
|
||||||
let gameDirectoryURL = DatabaseManager.saveStatesDirectoryURL.appendingPathComponent(game.identifier)
|
let gameDirectoryURL = DatabaseManager.saveStatesDirectoryURL.appendingPathComponent(game.identifier)
|
||||||
self.createDirectoryAtURLIfNeeded(gameDirectoryURL)
|
self.createDirectory(at: gameDirectoryURL)
|
||||||
|
|
||||||
return gameDirectoryURL
|
return gameDirectoryURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: - Private -
|
||||||
private extension DatabaseManager
|
private extension DatabaseManager
|
||||||
{
|
{
|
||||||
// MARK: - Saving -
|
class func createDirectory(at url: URL)
|
||||||
|
|
||||||
func save()
|
|
||||||
{
|
|
||||||
let backgroundTaskIdentifier = RSTBeginBackgroundTask("Save Database Task")
|
|
||||||
|
|
||||||
self.validationManagedObjectContext.performAndWait {
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
try self.validationManagedObjectContext.save()
|
|
||||||
}
|
|
||||||
catch let error as NSError
|
|
||||||
{
|
|
||||||
print("Failed to save validation context:", error)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Update main managed object context
|
|
||||||
self.managedObjectContext.performAndWait() {
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
try self.managedObjectContext.save()
|
|
||||||
}
|
|
||||||
catch let error as NSError
|
|
||||||
{
|
|
||||||
print("Failed to save main context:", error)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Save to disk
|
|
||||||
self.privateManagedObjectContext.perform() {
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
try self.privateManagedObjectContext.save()
|
|
||||||
}
|
|
||||||
catch let error as NSError
|
|
||||||
{
|
|
||||||
print("Failed to save private context to disk:", error)
|
|
||||||
}
|
|
||||||
|
|
||||||
RSTEndBackgroundTask(backgroundTaskIdentifier)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Validation -
|
|
||||||
|
|
||||||
func validateManagedObjectContextSave(_ managedObjectContext: NSManagedObjectContext)
|
|
||||||
{
|
|
||||||
// Remove deleted files from disk
|
|
||||||
for object in managedObjectContext.deletedObjects
|
|
||||||
{
|
|
||||||
var fileURLs = Set<URL>()
|
|
||||||
|
|
||||||
let temporaryObject = self.validationManagedObjectContext.object(with: object.objectID)
|
|
||||||
switch temporaryObject
|
|
||||||
{
|
|
||||||
case let game as Game:
|
|
||||||
fileURLs.insert(game.fileURL as URL)
|
|
||||||
|
|
||||||
case let saveState as SaveState:
|
|
||||||
fileURLs.insert(saveState.fileURL as URL)
|
|
||||||
fileURLs.insert(saveState.imageFileURL as URL)
|
|
||||||
|
|
||||||
default: break
|
|
||||||
}
|
|
||||||
|
|
||||||
for URL in fileURLs
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
try FileManager.default.removeItem(at: URL)
|
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
|
||||||
}
|
|
||||||
catch let error as NSError
|
|
||||||
{
|
|
||||||
print(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove empty collections
|
|
||||||
let collections = GameCollection.instancesWithPredicate(NSPredicate(format: "%K.@count == 0", GameCollection.Attributes.games.rawValue), inManagedObjectContext: self.validationManagedObjectContext, type: GameCollection.self)
|
|
||||||
|
|
||||||
for collection in collections
|
|
||||||
{
|
|
||||||
self.validationManagedObjectContext.delete(collection)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Notifications -
|
|
||||||
|
|
||||||
@objc func managedObjectContextWillSave(_ notification: Notification)
|
|
||||||
{
|
|
||||||
guard
|
|
||||||
let managedObjectContext = notification.object as? NSManagedObjectContext,
|
|
||||||
managedObjectContext.parent == self.validationManagedObjectContext
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
self.validationManagedObjectContext.performAndWait {
|
|
||||||
self.validateManagedObjectContextSave(managedObjectContext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func managedObjectContextDidSave(_ notification: Notification)
|
|
||||||
{
|
|
||||||
guard
|
|
||||||
let managedObjectContext = notification.object as? NSManagedObjectContext,
|
|
||||||
managedObjectContext.parent == self.validationManagedObjectContext
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
self.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - File Management -
|
|
||||||
|
|
||||||
class func createDirectoryAtURLIfNeeded(_ URL: Foundation.URL)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
try FileManager.default.createDirectory(at: URL, withIntermediateDirectories: true, attributes: nil)
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|||||||
@ -62,6 +62,39 @@ class Game: NSManagedObject, GameProtocol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Game
|
||||||
|
{
|
||||||
|
override public func prepareForDeletion()
|
||||||
|
{
|
||||||
|
super.prepareForDeletion()
|
||||||
|
|
||||||
|
guard FileManager.default.fileExists(atPath: self.fileURL.path) else { return }
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try FileManager.default.removeItem(at: self.fileURL)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let managedObjectContext = self.managedObjectContext
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
if managedObjectContext.hasChanges
|
||||||
|
{
|
||||||
|
managedObjectContext.saveWithErrorLogging()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension Game
|
extension Game
|
||||||
{
|
{
|
||||||
class func supportedTypeIdentifiers() -> Set<String>
|
class func supportedTypeIdentifiers() -> Set<String>
|
||||||
|
|||||||
@ -70,6 +70,25 @@ class SaveState: NSManagedObject, SaveStateProtocol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension SaveState
|
||||||
|
{
|
||||||
|
override public func prepareForDeletion()
|
||||||
|
{
|
||||||
|
super.prepareForDeletion()
|
||||||
|
|
||||||
|
guard FileManager.default.fileExists(atPath: self.fileURL.path) else { return }
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try FileManager.default.removeItem(at: self.fileURL)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension SaveState
|
extension SaveState
|
||||||
{
|
{
|
||||||
@NSManaged private var primitiveFilename: String
|
@NSManaged private var primitiveFilename: String
|
||||||
|
|||||||
@ -53,15 +53,14 @@ class GamePickerController: NSObject
|
|||||||
|
|
||||||
let importAction = UIAlertAction(title: NSLocalizedString("Import", comment: ""), style: .default) { action in
|
let importAction = UIAlertAction(title: NSLocalizedString("Import", comment: ""), style: .default) { action in
|
||||||
|
|
||||||
let documentsDirectoryURL = DatabaseManager.databaseDirectoryURL.deletingLastPathComponent()
|
let documentsDirectoryURL = DatabaseManager.defaultDirectoryURL().deletingLastPathComponent()
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
let contents = try FileManager.default.contentsOfDirectory(at: documentsDirectoryURL, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
|
let contents = try FileManager.default.contentsOfDirectory(at: documentsDirectoryURL, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
|
||||||
|
|
||||||
let managedObjectContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
DatabaseManager.shared.performBackgroundTask { (context) in
|
||||||
managedObjectContext.perform() {
|
let gameURLs = contents.filter({ GameCollection.gameSystemCollectionForPathExtension($0.pathExtension, inManagedObjectContext: context).identifier != GameType.delta.rawValue })
|
||||||
let gameURLs = contents.filter({ GameCollection.gameSystemCollectionForPathExtension($0.pathExtension, inManagedObjectContext: managedObjectContext).identifier != GameType.delta.rawValue })
|
|
||||||
self.importGamesAtURLs(gameURLs)
|
self.importGamesAtURLs(gameURLs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,12 +86,12 @@ class GamePickerController: NSObject
|
|||||||
|
|
||||||
private func importGamesAtURLs(_ URLs: [URL])
|
private func importGamesAtURLs(_ URLs: [URL])
|
||||||
{
|
{
|
||||||
DatabaseManager.sharedManager.importGamesAtURLs(URLs) { identifiers in
|
DatabaseManager.shared.importGames(at: URLs) { identifiers in
|
||||||
|
|
||||||
DatabaseManager.sharedManager.managedObjectContext.perform() {
|
DatabaseManager.shared.viewContext.perform() {
|
||||||
|
|
||||||
let predicate = NSPredicate(format: "%K IN (%@)", Game.Attributes.identifier.rawValue, identifiers)
|
let predicate = NSPredicate(format: "%K IN (%@)", Game.Attributes.identifier.rawValue, identifiers)
|
||||||
let games = Game.instancesWithPredicate(predicate, inManagedObjectContext: DatabaseManager.sharedManager.managedObjectContext, type: Game.self)
|
let games = Game.instancesWithPredicate(predicate, inManagedObjectContext: DatabaseManager.shared.viewContext, type: Game.self)
|
||||||
|
|
||||||
self.delegate?.gamePickerController(self, didImportGames: games)
|
self.delegate?.gamePickerController(self, didImportGames: games)
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,6 @@
|
|||||||
BF65E8631CEE5C6A00CD3247 /* Cheat.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF65E8621CEE5C6A00CD3247 /* Cheat.swift */; };
|
BF65E8631CEE5C6A00CD3247 /* Cheat.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF65E8621CEE5C6A00CD3247 /* Cheat.swift */; };
|
||||||
BF70798C1B6B464B0019077C /* ZipZap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; };
|
BF70798C1B6B464B0019077C /* ZipZap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; };
|
||||||
BF70798D1B6B464B0019077C /* ZipZap.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
BF70798D1B6B464B0019077C /* ZipZap.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
BF762E9E1BC19D31002C8866 /* DatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF762E9D1BC19D31002C8866 /* DatabaseManager.swift */; };
|
|
||||||
BF762EAB1BC1B076002C8866 /* NSManagedObject+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF762EAA1BC1B076002C8866 /* NSManagedObject+Conveniences.swift */; };
|
BF762EAB1BC1B076002C8866 /* NSManagedObject+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF762EAA1BC1B076002C8866 /* NSManagedObject+Conveniences.swift */; };
|
||||||
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */; };
|
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */; };
|
||||||
BF7AE8081C2E858400B1B5BC /* PauseMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8041C2E858400B1B5BC /* PauseMenuViewController.swift */; };
|
BF7AE8081C2E858400B1B5BC /* PauseMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8041C2E858400B1B5BC /* PauseMenuViewController.swift */; };
|
||||||
@ -51,6 +50,7 @@
|
|||||||
BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAA1FEC1B8AA4FA00495943 /* Settings.swift */; };
|
BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAA1FEC1B8AA4FA00495943 /* Settings.swift */; };
|
||||||
BFAA1FF41B8AD7F900495943 /* ControllersSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAA1FF31B8AD7F900495943 /* ControllersSettingsViewController.swift */; };
|
BFAA1FF41B8AD7F900495943 /* ControllersSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAA1FF31B8AD7F900495943 /* ControllersSettingsViewController.swift */; };
|
||||||
BFB141181BE46934004FBF46 /* GameCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFB141171BE46934004FBF46 /* GameCollectionViewDataSource.swift */; };
|
BFB141181BE46934004FBF46 /* GameCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFB141171BE46934004FBF46 /* GameCollectionViewDataSource.swift */; };
|
||||||
|
BFBAA86A1D5A483900A29C1B /* DatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBAA8691D5A483900A29C1B /* DatabaseManager.swift */; };
|
||||||
BFC2731A1BE6152200D22B05 /* GameCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC273171BE6152200D22B05 /* GameCollection.swift */; };
|
BFC2731A1BE6152200D22B05 /* GameCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC273171BE6152200D22B05 /* GameCollection.swift */; };
|
||||||
BFC9B7391CEFCD34008629BB /* CheatsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */; };
|
BFC9B7391CEFCD34008629BB /* CheatsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */; };
|
||||||
BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */; };
|
BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */; };
|
||||||
@ -126,7 +126,6 @@
|
|||||||
BF65E8621CEE5C6A00CD3247 /* Cheat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cheat.swift; sourceTree = "<group>"; };
|
BF65E8621CEE5C6A00CD3247 /* Cheat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cheat.swift; sourceTree = "<group>"; };
|
||||||
BF6BB2451BB73FE800CCF94A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
BF6BB2451BB73FE800CCF94A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
BF70798B1B6B464B0019077C /* ZipZap.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ZipZap.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
BF70798B1B6B464B0019077C /* ZipZap.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ZipZap.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
BF762E9D1BC19D31002C8866 /* DatabaseManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseManager.swift; sourceTree = "<group>"; };
|
|
||||||
BF762EAA1BC1B076002C8866 /* NSManagedObject+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Conveniences.swift"; sourceTree = "<group>"; };
|
BF762EAA1BC1B076002C8866 /* NSManagedObject+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Conveniences.swift"; sourceTree = "<group>"; };
|
||||||
BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UILabel+FontSize.swift"; sourceTree = "<group>"; };
|
BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UILabel+FontSize.swift"; sourceTree = "<group>"; };
|
||||||
BF7AE8041C2E858400B1B5BC /* PauseMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PauseMenuViewController.swift; path = "Pause Menu/PauseMenuViewController.swift"; sourceTree = "<group>"; };
|
BF7AE8041C2E858400B1B5BC /* PauseMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PauseMenuViewController.swift; path = "Pause Menu/PauseMenuViewController.swift"; sourceTree = "<group>"; };
|
||||||
@ -138,6 +137,7 @@
|
|||||||
BFAA1FEC1B8AA4FA00495943 /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
|
BFAA1FEC1B8AA4FA00495943 /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
|
||||||
BFAA1FF31B8AD7F900495943 /* ControllersSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControllersSettingsViewController.swift; sourceTree = "<group>"; };
|
BFAA1FF31B8AD7F900495943 /* ControllersSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControllersSettingsViewController.swift; sourceTree = "<group>"; };
|
||||||
BFB141171BE46934004FBF46 /* GameCollectionViewDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameCollectionViewDataSource.swift; path = "Collection View/GameCollectionViewDataSource.swift"; sourceTree = "<group>"; };
|
BFB141171BE46934004FBF46 /* GameCollectionViewDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameCollectionViewDataSource.swift; path = "Collection View/GameCollectionViewDataSource.swift"; sourceTree = "<group>"; };
|
||||||
|
BFBAA8691D5A483900A29C1B /* DatabaseManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseManager.swift; sourceTree = "<group>"; };
|
||||||
BFC134E01AAD82460087AD7B /* SNESDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SNESDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
BFC134E01AAD82460087AD7B /* SNESDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SNESDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
BFC273171BE6152200D22B05 /* GameCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollection.swift; sourceTree = "<group>"; };
|
BFC273171BE6152200D22B05 /* GameCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollection.swift; sourceTree = "<group>"; };
|
||||||
BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheatsViewController.swift; path = "Pause Menu/Cheats/CheatsViewController.swift"; sourceTree = "<group>"; };
|
BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheatsViewController.swift; path = "Pause Menu/Cheats/CheatsViewController.swift"; sourceTree = "<group>"; };
|
||||||
@ -229,7 +229,7 @@
|
|||||||
BF4566E41BC0902E007BFA1A /* Database */ = {
|
BF4566E41BC0902E007BFA1A /* Database */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
BF762E9D1BC19D31002C8866 /* DatabaseManager.swift */,
|
BFBAA8691D5A483900A29C1B /* DatabaseManager.swift */,
|
||||||
BF4566E51BC09033007BFA1A /* Model */,
|
BF4566E51BC09033007BFA1A /* Model */,
|
||||||
);
|
);
|
||||||
path = Database;
|
path = Database;
|
||||||
@ -583,6 +583,7 @@
|
|||||||
BFAA1FF41B8AD7F900495943 /* ControllersSettingsViewController.swift in Sources */,
|
BFAA1FF41B8AD7F900495943 /* ControllersSettingsViewController.swift in Sources */,
|
||||||
BF353FF91C5D870B00C1184C /* PauseItem.swift in Sources */,
|
BF353FF91C5D870B00C1184C /* PauseItem.swift in Sources */,
|
||||||
BF27CC971BCC890700A20D89 /* GamesCollectionViewController.swift in Sources */,
|
BF27CC971BCC890700A20D89 /* GamesCollectionViewController.swift in Sources */,
|
||||||
|
BFBAA86A1D5A483900A29C1B /* DatabaseManager.swift in Sources */,
|
||||||
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */,
|
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */,
|
||||||
BF7AE81E1C2E984300B1B5BC /* GridCollectionViewCell.swift in Sources */,
|
BF7AE81E1C2E984300B1B5BC /* GridCollectionViewCell.swift in Sources */,
|
||||||
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,
|
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,
|
||||||
@ -600,7 +601,6 @@
|
|||||||
BF02BD001D361BD1000892F2 /* NSFetchedResultsController+Conveniences.m in Sources */,
|
BF02BD001D361BD1000892F2 /* NSFetchedResultsController+Conveniences.m in Sources */,
|
||||||
BFFC464C1D5998D600AF2CC6 /* CheatTableViewCell.swift in Sources */,
|
BFFC464C1D5998D600AF2CC6 /* CheatTableViewCell.swift in Sources */,
|
||||||
BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */,
|
BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */,
|
||||||
BF762E9E1BC19D31002C8866 /* DatabaseManager.swift in Sources */,
|
|
||||||
BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */,
|
BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */,
|
||||||
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */,
|
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */,
|
||||||
BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */,
|
BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */,
|
||||||
|
|||||||
@ -26,14 +26,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate
|
|||||||
|
|
||||||
// Database
|
// Database
|
||||||
|
|
||||||
let semaphore = DispatchSemaphore(value: 0)
|
DatabaseManager.shared.loadPersistentStores { (description, error) in
|
||||||
|
|
||||||
DatabaseManager.sharedManager.startWithCompletion { performingMigration in
|
|
||||||
semaphore.signal()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore.wait()
|
|
||||||
|
|
||||||
// Controllers
|
// Controllers
|
||||||
ExternalControllerManager.shared.startMonitoringExternalControllers()
|
ExternalControllerManager.shared.startMonitoringExternalControllers()
|
||||||
|
|
||||||
|
|||||||
@ -453,7 +453,7 @@ extension GameViewController: CheatsViewControllerDelegate
|
|||||||
self.pauseEmulation()
|
self.pauseEmulation()
|
||||||
}
|
}
|
||||||
|
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
backgroundContext.performAndWait {
|
backgroundContext.performAndWait {
|
||||||
|
|
||||||
let predicate = NSPredicate(format: "%K == %@", Cheat.Attributes.game.rawValue, game)
|
let predicate = NSPredicate(format: "%K == %@", Cheat.Attributes.game.rawValue, game)
|
||||||
|
|||||||
@ -45,7 +45,7 @@ class GamesViewController: UIViewController
|
|||||||
let fetchRequest = GameCollection.rst_fetchRequest()
|
let fetchRequest = GameCollection.rst_fetchRequest()
|
||||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: GameCollection.Attributes.index.rawValue, ascending: true)]
|
fetchRequest.sortDescriptors = [NSSortDescriptor(key: GameCollection.Attributes.index.rawValue, ascending: true)]
|
||||||
|
|
||||||
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.sharedManager.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
|
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: nil, cacheName: nil)
|
||||||
|
|
||||||
super.init(coder: aDecoder)
|
super.init(coder: aDecoder)
|
||||||
|
|
||||||
|
|||||||
@ -97,7 +97,7 @@ private extension CheatsViewController
|
|||||||
fetchRequest.predicate = NSPredicate(format: "%K == %@", Cheat.Attributes.game.rawValue, self.game)
|
fetchRequest.predicate = NSPredicate(format: "%K == %@", Cheat.Attributes.game.rawValue, self.game)
|
||||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: Cheat.Attributes.name.rawValue, ascending: true)]
|
fetchRequest.sortDescriptors = [NSSortDescriptor(key: Cheat.Attributes.name.rawValue, ascending: true)]
|
||||||
|
|
||||||
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.sharedManager.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
|
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: nil, cacheName: nil)
|
||||||
self.fetchedResultsController.delegate = self
|
self.fetchedResultsController.delegate = self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,11 +130,10 @@ private extension CheatsViewController
|
|||||||
{
|
{
|
||||||
self.delegate?.cheatsViewController(self, deactivateCheat: cheat)
|
self.delegate?.cheatsViewController(self, deactivateCheat: cheat)
|
||||||
|
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
DatabaseManager.shared.performBackgroundTask { (context) in
|
||||||
backgroundContext.perform {
|
let temporaryCheat = context.object(with: cheat.objectID)
|
||||||
let temporaryCheat = backgroundContext.object(with: cheat.objectID)
|
context.delete(temporaryCheat)
|
||||||
backgroundContext.delete(temporaryCheat)
|
context.saveWithErrorLogging()
|
||||||
backgroundContext.saveWithErrorLogging()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,7 +192,7 @@ extension CheatsViewController
|
|||||||
{
|
{
|
||||||
let cheat = self.fetchedResultsController.object(at: indexPath) as! Cheat
|
let cheat = self.fetchedResultsController.object(at: indexPath) as! Cheat
|
||||||
|
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
backgroundContext.performAndWait {
|
backgroundContext.performAndWait {
|
||||||
let temporaryCheat = backgroundContext.object(with: cheat.objectID) as! Cheat
|
let temporaryCheat = backgroundContext.object(with: cheat.objectID) as! Cheat
|
||||||
temporaryCheat.enabled = !temporaryCheat.enabled
|
temporaryCheat.enabled = !temporaryCheat.enabled
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class EditCheatViewController: UITableViewController
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var mutableCheat: Cheat!
|
private var mutableCheat: Cheat!
|
||||||
private var managedObjectContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
private var managedObjectContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
|
|
||||||
@IBOutlet private var nameTextField: UITextField!
|
@IBOutlet private var nameTextField: UITextField!
|
||||||
@IBOutlet private var typeSegmentedControl: UISegmentedControl!
|
@IBOutlet private var typeSegmentedControl: UISegmentedControl!
|
||||||
@ -76,11 +76,10 @@ class EditCheatViewController: UITableViewController
|
|||||||
let deleteAction = UIPreviewAction(title: NSLocalizedString("Delete", comment: ""), style: .destructive) { [unowned self] (action, viewController) in
|
let deleteAction = UIPreviewAction(title: NSLocalizedString("Delete", comment: ""), style: .destructive) { [unowned self] (action, viewController) in
|
||||||
self.delegate?.editCheatViewController(self, deactivateCheat: cheat)
|
self.delegate?.editCheatViewController(self, deactivateCheat: cheat)
|
||||||
|
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
DatabaseManager.shared.performBackgroundTask { (context) in
|
||||||
backgroundContext.perform {
|
let temporaryCheat = context.object(with: cheat.objectID)
|
||||||
let temporaryCheat = backgroundContext.object(with: cheat.objectID)
|
context.delete(temporaryCheat)
|
||||||
backgroundContext.delete(temporaryCheat)
|
context.saveWithErrorLogging()
|
||||||
backgroundContext.saveWithErrorLogging()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -168,7 +168,7 @@ private extension SaveStatesViewController
|
|||||||
fetchRequest.predicate = NSPredicate(format: "%K == %@", SaveState.Attributes.game.rawValue, self.game)
|
fetchRequest.predicate = NSPredicate(format: "%K == %@", SaveState.Attributes.game.rawValue, self.game)
|
||||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: SaveState.Attributes.type.rawValue, ascending: true), NSSortDescriptor(key: SaveState.Attributes.creationDate.rawValue, ascending: true)]
|
fetchRequest.sortDescriptors = [NSSortDescriptor(key: SaveState.Attributes.type.rawValue, ascending: true), NSSortDescriptor(key: SaveState.Attributes.creationDate.rawValue, ascending: true)]
|
||||||
|
|
||||||
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.sharedManager.managedObjectContext, sectionNameKeyPath: SaveState.Attributes.type.rawValue, cacheName: nil)
|
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: SaveState.Attributes.type.rawValue, cacheName: nil)
|
||||||
self.fetchedResultsController.delegate = self
|
self.fetchedResultsController.delegate = self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +275,7 @@ private extension SaveStatesViewController
|
|||||||
{
|
{
|
||||||
var saveState: SaveState!
|
var saveState: SaveState!
|
||||||
|
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
backgroundContext.performAndWait {
|
backgroundContext.performAndWait {
|
||||||
|
|
||||||
let game = backgroundContext.object(with: self.game.objectID) as! Game
|
let game = backgroundContext.object(with: self.game.objectID) as! Game
|
||||||
@ -324,14 +324,12 @@ private extension SaveStatesViewController
|
|||||||
let confirmationAlertController = UIAlertController(title: NSLocalizedString("Delete Save State?", comment: ""), message: NSLocalizedString("Are you sure you want to delete this save state? This cannot be undone.", comment: ""), preferredStyle: .alert)
|
let confirmationAlertController = UIAlertController(title: NSLocalizedString("Delete Save State?", comment: ""), message: NSLocalizedString("Are you sure you want to delete this save state? This cannot be undone.", comment: ""), preferredStyle: .alert)
|
||||||
confirmationAlertController.addAction(UIAlertAction(title: NSLocalizedString("Delete", comment: ""), style: .default, handler: { action in
|
confirmationAlertController.addAction(UIAlertAction(title: NSLocalizedString("Delete", comment: ""), style: .default, handler: { action in
|
||||||
|
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
DatabaseManager.shared.performBackgroundTask { (context) in
|
||||||
backgroundContext.perform {
|
let temporarySaveState = context.object(with: saveState.objectID)
|
||||||
let temporarySaveState = backgroundContext.object(with: saveState.objectID)
|
context.delete(temporarySaveState)
|
||||||
backgroundContext.delete(temporarySaveState)
|
context.saveWithErrorLogging()
|
||||||
backgroundContext.saveWithErrorLogging()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}))
|
}))
|
||||||
confirmationAlertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil))
|
confirmationAlertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil))
|
||||||
|
|
||||||
@ -370,13 +368,11 @@ private extension SaveStatesViewController
|
|||||||
text = nil
|
text = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
DatabaseManager.shared.performBackgroundTask { (context) in
|
||||||
backgroundContext.perform {
|
let saveState = context.object(with: selectedSaveState.objectID) as! SaveState
|
||||||
|
|
||||||
let saveState = backgroundContext.object(with: selectedSaveState.objectID) as! SaveState
|
|
||||||
saveState.name = text
|
saveState.name = text
|
||||||
|
|
||||||
backgroundContext.saveWithErrorLogging()
|
context.saveWithErrorLogging()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.selectedSaveState = nil
|
self.selectedSaveState = nil
|
||||||
@ -388,14 +384,12 @@ private extension SaveStatesViewController
|
|||||||
alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil))
|
alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil))
|
||||||
alertController.addAction(UIAlertAction(title: NSLocalizedString("Change", comment: ""), style: .default, handler: { (action) in
|
alertController.addAction(UIAlertAction(title: NSLocalizedString("Change", comment: ""), style: .default, handler: { (action) in
|
||||||
|
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
DatabaseManager.shared.performBackgroundTask { (context) in
|
||||||
backgroundContext.perform {
|
let game = context.object(with: self.game.objectID) as! Game
|
||||||
|
|
||||||
let game = backgroundContext.object(with: self.game.objectID) as! Game
|
|
||||||
|
|
||||||
if let saveState = saveState
|
if let saveState = saveState
|
||||||
{
|
{
|
||||||
let previewSaveState = backgroundContext.object(with: saveState.objectID) as! SaveState
|
let previewSaveState = context.object(with: saveState.objectID) as! SaveState
|
||||||
game.previewSaveState = previewSaveState
|
game.previewSaveState = previewSaveState
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -403,9 +397,8 @@ private extension SaveStatesViewController
|
|||||||
game.previewSaveState = nil
|
game.previewSaveState = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
backgroundContext.saveWithErrorLogging()
|
context.saveWithErrorLogging()
|
||||||
}
|
}
|
||||||
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
self.present(alertController, animated: true, completion: nil)
|
self.present(alertController, animated: true, completion: nil)
|
||||||
@ -413,7 +406,7 @@ private extension SaveStatesViewController
|
|||||||
|
|
||||||
func lockSaveState(_ saveState: SaveState)
|
func lockSaveState(_ saveState: SaveState)
|
||||||
{
|
{
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
backgroundContext.performAndWait() {
|
backgroundContext.performAndWait() {
|
||||||
let temporarySaveState = backgroundContext.object(with: saveState.objectID) as! SaveState
|
let temporarySaveState = backgroundContext.object(with: saveState.objectID) as! SaveState
|
||||||
temporarySaveState.type = .locked
|
temporarySaveState.type = .locked
|
||||||
@ -423,7 +416,7 @@ private extension SaveStatesViewController
|
|||||||
|
|
||||||
func unlockSaveState(_ saveState: SaveState)
|
func unlockSaveState(_ saveState: SaveState)
|
||||||
{
|
{
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
backgroundContext.performAndWait() {
|
backgroundContext.performAndWait() {
|
||||||
let temporarySaveState = backgroundContext.object(with: saveState.objectID) as! SaveState
|
let temporarySaveState = backgroundContext.object(with: saveState.objectID) as! SaveState
|
||||||
temporarySaveState.type = .general
|
temporarySaveState.type = .general
|
||||||
@ -692,7 +685,7 @@ extension SaveStatesViewController
|
|||||||
{
|
{
|
||||||
case .auto: break
|
case .auto: break
|
||||||
case .general:
|
case .general:
|
||||||
let backgroundContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
backgroundContext.performAndWait() {
|
backgroundContext.performAndWait() {
|
||||||
let temporarySaveState = backgroundContext.object(with: saveState.objectID) as! SaveState
|
let temporarySaveState = backgroundContext.object(with: saveState.objectID) as! SaveState
|
||||||
self.updateSaveState(temporarySaveState)
|
self.updateSaveState(temporarySaveState)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user