diff --git a/Memola/Canvas/Contexts/GraphicContext.swift b/Memola/Canvas/Contexts/GraphicContext.swift index 758cec6..cf6f565 100644 --- a/Memola/Canvas/Contexts/GraphicContext.swift +++ b/Memola/Canvas/Contexts/GraphicContext.swift @@ -62,13 +62,21 @@ final class GraphicContext: @unchecked Sendable { extension GraphicContext { func loadStrokes(_ bounds: CGRect) { guard let object else { return } + let queue = OperationQueue() + queue.qualityOfService = .userInteractive self.strokes = object.strokes.compactMap { stroke -> Stroke? in guard let stroke = stroke as? StrokeObject else { return nil } let _stroke = Stroke(object: stroke) if _stroke.isVisible(in: bounds) { - _stroke.loadQuads() - withPersistence(\.backgroundContext) { [stroke] context in - context.refresh(stroke, mergeChanges: false) + let id = stroke.objectID + queue.addOperation { + withPersistenceSync(\.newBackgroundContext) { [_stroke] context in + guard let stroke = try? context.existingObject(with: id) as? StrokeObject else { return } + _stroke.loadQuads(from: stroke) + } + withPersistence(\.backgroundContext) { [stroke] context in + context.refresh(stroke, mergeChanges: false) + } } } else { withPersistence(\.backgroundContext) { [stroke] context in @@ -78,6 +86,7 @@ extension GraphicContext { } return _stroke } + queue.waitUntilAllOperationsAreFinished() } func loadQuads(_ bounds: CGRect) { diff --git a/Memola/Canvas/Geometries/Stroke/Stroke.swift b/Memola/Canvas/Geometries/Stroke/Stroke.swift index 712f7a8..0a13a11 100644 --- a/Memola/Canvas/Geometries/Stroke/Stroke.swift +++ b/Memola/Canvas/Geometries/Stroke/Stroke.swift @@ -98,6 +98,13 @@ extension Stroke { } } + func loadQuads(from object: StrokeObject) { + quads = object.quads.compactMap { quad in + guard let quad = quad as? QuadObject else { return nil } + return Quad(object: quad) + } + } + func addQuad(at point: CGPoint, rotation: CGFloat, shape: QuadShape) -> Quad { let quad = Quad( origin: point, diff --git a/Memola/Persistence/Core/Persistence.swift b/Memola/Persistence/Core/Persistence.swift index 4cb4a9a..5ebac21 100644 --- a/Memola/Persistence/Core/Persistence.swift +++ b/Memola/Persistence/Core/Persistence.swift @@ -26,6 +26,13 @@ final class Persistence { return context }() + var newBackgroundContext: NSManagedObjectContext { + let context = persistentContainer.newBackgroundContext() + context.undoManager = nil + context.automaticallyMergesChangesFromParent = true + return context + } + lazy var persistentContainer: NSPersistentContainer = { let persistentStore = NSPersistentStoreDescription() persistentStore.shouldMigrateStoreAutomatically = true @@ -83,3 +90,14 @@ func withPersistence(_ keypath: KeyPath, _ } } } + +func withPersistenceSync(_ keypath: KeyPath, _ task: @escaping (NSManagedObjectContext) throws -> Void) { + let context = Persistence.shared[keyPath: keypath] + context.performAndWait { + do { + try task(context) + } catch { + NSLog("[Memola] - \(error.localizedDescription)") + } + } +}