mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-07-12 15:52:41 +02:00
refactor: clean up persistence related code
This commit is contained in:
@@ -12,7 +12,7 @@ struct MemolaApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
MemosView()
|
||||
.environment(\.managedObjectContext, Persistence.context)
|
||||
.persistence(\.viewContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ final class GraphicContext: @unchecked Sendable {
|
||||
func undoGraphic() {
|
||||
guard !strokes.isEmpty else { return }
|
||||
let stroke = strokes.removeLast()
|
||||
Persistence.backgroundContext.perform {
|
||||
withPersistence(\.backgroundContext) { [stroke] context in
|
||||
stroke.object?.graphicContext = nil
|
||||
Persistence.saveIfNeededInBackground()
|
||||
try context.saveIfNeeded()
|
||||
}
|
||||
previousStroke = nil
|
||||
}
|
||||
@@ -50,9 +50,9 @@ final class GraphicContext: @unchecked Sendable {
|
||||
switch event {
|
||||
case .stroke(let stroke):
|
||||
strokes.append(stroke)
|
||||
Persistence.backgroundContext.perform { [weak self] in
|
||||
withPersistence(\.backgroundContext) { [weak self, stroke] context in
|
||||
stroke.object?.graphicContext = self?.object
|
||||
Persistence.saveIfNeededInBackground()
|
||||
try context.saveIfNeeded()
|
||||
}
|
||||
previousStroke = nil
|
||||
}
|
||||
@@ -95,8 +95,8 @@ extension GraphicContext {
|
||||
createdAt: .now,
|
||||
thickness: pen.thickness
|
||||
)
|
||||
Persistence.backgroundContext.perform { [graphicContext = object, _stroke = stroke] in
|
||||
let stroke = StrokeObject(context: Persistence.backgroundContext)
|
||||
withPersistence(\.backgroundContext) { [graphicContext = object, _stroke = stroke] context in
|
||||
let stroke = StrokeObject(\.backgroundContext)
|
||||
stroke.color = _stroke.color
|
||||
stroke.style = _stroke.style
|
||||
stroke.thickness = _stroke.thickness
|
||||
@@ -125,12 +125,12 @@ extension GraphicContext {
|
||||
currentStroke.finish(at: point)
|
||||
let saveIndex = currentStroke.batchIndex
|
||||
let quads = Array(currentStroke.quads[saveIndex..<currentStroke.quads.count])
|
||||
Persistence.backgroundContext.perform { [currentStroke, quads] in
|
||||
withPersistence(\.backgroundContext) { [currentStroke, quads] context in
|
||||
currentStroke.saveQuads(for: quads)
|
||||
Persistence.saveIfNeededInBackground()
|
||||
try context.saveIfNeeded()
|
||||
if let stroke = currentStroke.object {
|
||||
currentStroke.quads.removeAll()
|
||||
Persistence.backgroundContext.refresh(stroke, mergeChanges: false)
|
||||
context.refresh(stroke, mergeChanges: false)
|
||||
}
|
||||
}
|
||||
previousStroke = currentStroke
|
||||
@@ -141,12 +141,12 @@ extension GraphicContext {
|
||||
func cancelStroke() {
|
||||
if !strokes.isEmpty {
|
||||
let stroke = strokes.removeLast()
|
||||
Persistence.backgroundContext.perform { [graphicContext = object, _stroke = stroke] in
|
||||
withPersistence(\.backgroundContext) { [graphicContext = object, _stroke = stroke] context in
|
||||
if let stroke = _stroke.object {
|
||||
graphicContext?.strokes.remove(stroke)
|
||||
Persistence.backgroundContext.delete(stroke)
|
||||
context.delete(stroke)
|
||||
}
|
||||
Persistence.saveIfNeededInBackground()
|
||||
try context.saveIfNeeded()
|
||||
}
|
||||
}
|
||||
currentStroke = nil
|
||||
|
||||
@@ -44,17 +44,17 @@ final class Canvas: ObservableObject, Identifiable, @unchecked Sendable {
|
||||
// MARK: - Actions
|
||||
extension Canvas {
|
||||
func load() {
|
||||
Persistence.backgroundContext.perform { [weak self, canvasID] in
|
||||
withPersistence(\.backgroundContext) { [weak self, canvasID] context in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.state = .loading
|
||||
}
|
||||
guard let canvas = Persistence.backgroundContext.object(with: canvasID) as? CanvasObject else {
|
||||
guard let canvas = context.object(with: canvasID) as? CanvasObject else {
|
||||
return
|
||||
}
|
||||
let graphicContext = canvas.graphicContext
|
||||
self?.graphicContext.object = graphicContext
|
||||
self?.graphicContext.load()
|
||||
Persistence.backgroundContext.refresh(canvas, mergeChanges: false)
|
||||
context.refresh(canvas, mergeChanges: false)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.state = .loaded
|
||||
}
|
||||
|
||||
@@ -104,14 +104,14 @@ final class Stroke: @unchecked Sendable {
|
||||
quads.removeLast(dropCount)
|
||||
let quads = Array(quads[batchIndex..<index])
|
||||
batchIndex = index
|
||||
Persistence.backgroundContext.perform { [weak self, quads] in
|
||||
withPersistence(\.backgroundContext) { [weak self, quads] context in
|
||||
self?.saveQuads(for: quads)
|
||||
}
|
||||
}
|
||||
|
||||
func saveQuads(for quads: [Quad]) {
|
||||
for _quad in quads {
|
||||
let quad = QuadObject(context: Persistence.backgroundContext)
|
||||
let quad = QuadObject(\.backgroundContext)
|
||||
quad.originX = _quad.originX
|
||||
quad.originY = _quad.originY
|
||||
quad.size = _quad.size
|
||||
|
||||
@@ -52,14 +52,14 @@ class History: ObservableObject {
|
||||
for event in redoStack {
|
||||
switch event {
|
||||
case .stroke(let _stroke):
|
||||
Persistence.backgroundContext.perform {
|
||||
withPersistence(\.backgroundContext) { context in
|
||||
if let stroke = _stroke.object {
|
||||
Persistence.backgroundContext.delete(stroke)
|
||||
context.delete(stroke)
|
||||
}
|
||||
try context.saveIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
Persistence.saveIfNeeded()
|
||||
redoStack.removeAll()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// NSManagedObject++.swift
|
||||
// Memola
|
||||
//
|
||||
// Created by Dscyre Scotti on 5/11/24.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
import Foundation
|
||||
|
||||
extension NSManagedObject {
|
||||
convenience init(_ keyPath: KeyPath<Persistence, NSManagedObjectContext>) {
|
||||
self.init(context: Persistence.shared[keyPath: keyPath])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// NSManagedObjectContext++.swift
|
||||
// Memola
|
||||
//
|
||||
// Created by Dscyre Scotti on 5/11/24.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
extension NSManagedObjectContext {
|
||||
func saveIfNeeded() throws {
|
||||
if hasChanges {
|
||||
try save()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// View++.swift
|
||||
// Memola
|
||||
//
|
||||
// Created by Dscyre Scotti on 5/11/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
import Foundation
|
||||
|
||||
extension View {
|
||||
func persistence(_ keyPath: KeyPath<Persistence, NSManagedObjectContext>) -> some View {
|
||||
environment(\.managedObjectContext, Persistence.shared[keyPath: keyPath])
|
||||
}
|
||||
}
|
||||
@@ -8,29 +8,24 @@
|
||||
import CoreData
|
||||
import Foundation
|
||||
|
||||
class Persistence {
|
||||
final class Persistence {
|
||||
private let modelName = "MemolaModel"
|
||||
|
||||
static let shared: Persistence = Persistence()
|
||||
|
||||
private init() { }
|
||||
|
||||
static var context: NSManagedObjectContext = {
|
||||
shared.persistentContainer.viewContext
|
||||
}()
|
||||
|
||||
static var backgroundContext: NSManagedObjectContext = {
|
||||
let context = shared.persistentContainer.newBackgroundContext()
|
||||
context.undoManager = nil
|
||||
|
||||
// context.automaticallyMergesC hangesFromParent = true
|
||||
return context
|
||||
}()
|
||||
|
||||
private lazy var viewContext: NSManagedObjectContext = {
|
||||
lazy var viewContext: NSManagedObjectContext = {
|
||||
persistentContainer.viewContext
|
||||
}()
|
||||
|
||||
lazy var backgroundContext: NSManagedObjectContext = {
|
||||
let context = persistentContainer.newBackgroundContext()
|
||||
context.undoManager = nil
|
||||
context.automaticallyMergesChangesFromParent = true
|
||||
return context
|
||||
}()
|
||||
|
||||
lazy var persistentContainer: NSPersistentContainer = {
|
||||
let persistentStore = NSPersistentStoreDescription()
|
||||
persistentStore.shouldMigrateStoreAutomatically = true
|
||||
@@ -75,38 +70,16 @@ class Persistence {
|
||||
fatalError("[Memola]: \(error.localizedDescription)")
|
||||
}
|
||||
}()
|
||||
|
||||
static func performe(_ action: (NSManagedObjectContext) -> Void) {
|
||||
action(shared.viewContext)
|
||||
}
|
||||
|
||||
static func saveIfNeeded() {
|
||||
if context.hasChanges {
|
||||
do {
|
||||
try context.save()
|
||||
} catch {
|
||||
NSLog("[Memola] - \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func saveIfNeededInBackground() {
|
||||
if backgroundContext.hasChanges {
|
||||
do {
|
||||
try backgroundContext.save()
|
||||
} catch {
|
||||
NSLog("[Memola] - \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Persistence {
|
||||
static func background(_ task: @escaping (NSManagedObjectContext) async throws -> Void, errorHandler: ((Error) async -> Void)? = nil) async {
|
||||
// MARK: - Global Method
|
||||
func withPersistence(_ keypath: KeyPath<Persistence, NSManagedObjectContext>, _ task: @escaping (NSManagedObjectContext) throws -> Void) {
|
||||
let context = Persistence.shared[keyPath: keypath]
|
||||
context.perform {
|
||||
do {
|
||||
try await task(backgroundContext)
|
||||
try task(context)
|
||||
} catch {
|
||||
await errorHandler?(error)
|
||||
NSLog("[Memola] - \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user