Last active
June 25, 2019 01:56
-
-
Save austenstrine/c559f37686596f0a0af6700b33f1c661 to your computer and use it in GitHub Desktop.
An API for CoreData that allows safe access and mutation of "global" variables.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// AppManagedDataController.swift | |
// Yah-El | |
// | |
// Created by Austen Strine on 5/20/19. | |
// Copyright © 2019 GoGreen. All rights reserved. | |
// | |
import CoreData | |
// ***************************** | |
// * * | |
// * properties & init * | |
// * * | |
// ***************************** | |
/** | |
Used to safely access and mutate "global" CoreData variables from any context in the app. | |
*/ | |
class AppManagedDataController:Hashable, UsesAppData, UsesAppHelper, UsesAppNetwork, UsesAppDelegate, UsesPrintTrace, UsesPersistenceManager | |
{ | |
//hashable | |
static func == (lhs: AppManagedDataController, rhs: AppManagedDataController) -> Bool | |
{ | |
return lhs.hashValue == rhs.hashValue | |
} | |
var hashValue:Int | |
{ | |
return uniqueContext.hashValue | |
} | |
//class name access | |
let classForCoder = AppManagedDataController.self | |
//managed object properties | |
private typealias SELF = AppManagedDataController | |
private var uniqueContext:NSManagedObjectContext | |
var context:NSManagedObjectContext | |
{ | |
return uniqueContext | |
} | |
//new order in progress properties | |
private static var newOrder: NewOrder? = nil | |
var newOrder: NewOrder? { | |
get | |
{ | |
return objectGet(staticObject: &SELF.newOrder) | |
} | |
set(newValue) | |
{ | |
objectSet(staticObject: &SELF.newOrder, newValue: newValue) | |
} | |
} | |
private static var newOrderClient: Client? = nil | |
var newOrderClient: Client? { | |
get | |
{ | |
return objectGet(staticObject: &SELF.newOrderClient) | |
} | |
set(newValue) | |
{ | |
objectSet(staticObject: &SELF.newOrderClient, newValue: newValue) | |
} | |
} | |
private static var selectedBillingAddress: Address? = nil | |
var selectedBillingAddress: Address? { | |
get | |
{ | |
return objectGet(staticObject: &SELF.selectedBillingAddress) | |
} | |
set(newValue) | |
{ | |
objectSet(staticObject: &SELF.selectedBillingAddress, newValue: newValue) | |
} | |
} | |
private static var selectedShippingAddress: Address? = nil | |
var selectedShippingAddress: Address? { | |
get | |
{ | |
return objectGet(staticObject: &SELF.selectedShippingAddress) | |
} | |
set(newValue) | |
{ | |
objectSet(staticObject: &SELF.selectedShippingAddress, newValue: newValue) | |
} | |
} | |
private static var shippingAddresses: [Address] = [] | |
var shippingAddresses:[Address]{ | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.shippingAddresses) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.shippingAddresses, | |
newValue: newValue) | |
} | |
} | |
private static var billingAddresses: [Address] = [] | |
var billingAddresses:[Address]{ | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.billingAddresses) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.billingAddresses, | |
newValue: newValue) | |
} | |
} | |
private static var newOrderProducts: [OrderedProduct] = [] | |
var newOrderProducts: [OrderedProduct] { | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.newOrderProducts) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.newOrderProducts, | |
newValue: newValue) | |
} | |
} | |
//load/edit new order properties | |
var savedNewOrders: [NewOrder] | |
{ | |
get | |
{ | |
return collectionDynamicFetch(type: [NewOrder].self) | |
} | |
} | |
private static var queuedNewOrders: [NewOrder] = [] | |
var queuedNewOrders: [NewOrder] { | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.queuedNewOrders) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.queuedNewOrders, | |
newValue: newValue) | |
} | |
} | |
//order search and view properties | |
private static var orderSearchResults: [Order] = [] | |
var orderSearchResults: [Order] { | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.orderSearchResults) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.orderSearchResults, | |
newValue: newValue) | |
} | |
} | |
private static var recentlySubmittedOrders: [Order] = [] | |
var recentlySubmittedOrders: [Order] { | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.recentlySubmittedOrders) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.recentlySubmittedOrders, | |
newValue: newValue) | |
} | |
} | |
private static var viewOrder: Order? = nil | |
var viewOrder: Order? { | |
get | |
{ | |
return objectGet(staticObject: &SELF.viewOrder) | |
} | |
set(newValue) | |
{ | |
objectSet(staticObject: &SELF.viewOrder, newValue: newValue) | |
} | |
} | |
private static var viewChildOrders: [Order] = [] | |
var viewChildOrders: [Order] { | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.viewChildOrders) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.viewChildOrders, | |
newValue: newValue) | |
} | |
} | |
//client create, search, and view properties | |
private static var queuedNewClients: [CreateClient] = [] | |
var queuedNewClients: [CreateClient] { | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.queuedNewClients) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.queuedNewClients, | |
newValue: newValue) | |
} | |
} | |
private static var editCreateClient: CreateClient? = nil | |
var editCreateClient: CreateClient? { | |
get | |
{ | |
return objectGet(staticObject: &SELF.editCreateClient) | |
} | |
set(newValue) | |
{ | |
objectSet(staticObject: &SELF.editCreateClient, newValue: newValue) | |
} | |
} | |
private static var clientSearchResults: [Client] = [] | |
var clientSearchResults: [Client] { | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.clientSearchResults) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.clientSearchResults, | |
newValue: newValue) | |
} | |
} | |
private static var viewClient: Client? = nil | |
var viewClient: Client? { | |
get | |
{ | |
return objectGet(staticObject: &SELF.viewClient) | |
} | |
set(newValue) | |
{ | |
objectSet(staticObject: &SELF.viewClient, newValue: newValue) | |
} | |
} | |
//product search and view properties | |
private static var storedProductSearchResults: [StoredProduct] = [] | |
var storedProductSearchResults: [StoredProduct] { | |
get | |
{ | |
return collectionGet( | |
staticCollection: &SELF.storedProductSearchResults) | |
} | |
set(newValue) | |
{ | |
collectionSet( | |
staticCollection: &SELF.storedProductSearchResults, | |
newValue: newValue) | |
} | |
} | |
private static var viewStoredProduct: StoredProduct? = nil | |
var viewStoredProduct: StoredProduct? { | |
get | |
{ | |
return objectGet(staticObject: &SELF.viewStoredProduct) | |
} | |
set(newValue) | |
{ | |
objectSet(staticObject: &SELF.viewStoredProduct, newValue: newValue) | |
} | |
} | |
//initializer | |
init(context cntxt: NSManagedObjectContext) | |
{ | |
uniqueContext = cntxt | |
} | |
} | |
// ***************************** | |
// * * | |
// * private funcs * | |
// * * | |
// ***************************** | |
extension AppManagedDataController | |
{ | |
private func collectionGet<T:NSManagedObject>(staticCollection:inout [T]) -> [T] | |
{ | |
persistenceManager.saveLock.lock() | |
defer{persistenceManager.saveLock.unlock()} | |
for (index, item) in staticCollection.enumerated().reversed() | |
{ | |
if item.isDeleted | |
{ | |
staticCollection.remove(at: index) | |
} | |
} | |
var freshCollection = [T]() | |
for object in staticCollection | |
{ | |
let id = object.objectID | |
let freshObject = try! context.existingObject(with: id) as! T | |
context.refresh(freshObject, mergeChanges: false) | |
freshCollection.append(freshObject) | |
} | |
staticCollection = freshCollection | |
return staticCollection | |
} | |
private func collectionSet<T:NSManagedObject>(staticCollection:inout [T], newValue newCollection:[T]) | |
{ | |
//persistenceManager.saveLock.lock() | |
//defer{persistenceManager.saveLock.unlock()} | |
ensureWriteContext("\(type(of:staticCollection))") | |
staticCollection = newCollection | |
persistenceManager.save(context) | |
} | |
private func collectionDynamicFetch<T:NSManagedObject>(type: [T].Type) -> [T] | |
{ | |
persistenceManager.saveLock.lock() | |
defer{persistenceManager.saveLock.unlock()} | |
let placeholder:[T] = try! PersistenceManager.shared.fetch(T.self, context:context) | |
return placeholder | |
} | |
private func objectGet<T:NSManagedObject>(staticObject:inout T?) -> T? | |
{ | |
persistenceManager.saveLock.lock() | |
defer{persistenceManager.saveLock.unlock()} | |
if staticObject.exists | |
{ | |
if staticObject!.isDeleted | |
{ | |
staticObject = nil | |
return nil | |
} | |
let id = staticObject!.objectID | |
staticObject = try! context.existingObject(with: id) as! T | |
context.refresh(staticObject!, mergeChanges: false) | |
} | |
return staticObject | |
} | |
private func objectSet<T:NSManagedObject>(staticObject:inout T?, newValue newObject:T?) | |
{ | |
//persistenceManager.saveLock.lock() | |
//defer{persistenceManager.saveLock.unlock()} | |
ensureWriteContext("\(T.self)") | |
if newObject == nil | |
{ | |
staticObject = nil | |
return | |
} | |
staticObject = newObject | |
persistenceManager.save(context) | |
} | |
fileprivate func ensureWriteContext(_ type:String) | |
{ | |
guard context != persistenceManager.readContext else | |
{ | |
fatalError("Illegal write on the read context for \(type)!") | |
} | |
} | |
fileprivate func ensureWriteContext() | |
{ | |
guard context != persistenceManager.readContext else | |
{ | |
fatalError("Illegal write on the read context!") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment