mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-23 18:01:23 +01:00
create AppGroupsManager
This commit is contained in:
@@ -586,6 +586,10 @@
|
|||||||
B56E4EE523CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; };
|
B56E4EE523CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; };
|
||||||
B56E4EE623CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; };
|
B56E4EE623CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; };
|
||||||
B56E4EE723CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; };
|
B56E4EE723CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; };
|
||||||
|
B56ED34C263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56ED34B263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift */; };
|
||||||
|
B56ED34D263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56ED34B263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift */; };
|
||||||
|
B56ED34E263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56ED34B263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift */; };
|
||||||
|
B56ED34F263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56ED34B263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift */; };
|
||||||
B57D27BE1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
B57D27BE1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
||||||
B57D27BF1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
B57D27BF1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
||||||
B57D27C01D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
B57D27C01D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
||||||
@@ -1129,6 +1133,7 @@
|
|||||||
B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldStorableType.swift; sourceTree = "<group>"; };
|
B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldStorableType.swift; sourceTree = "<group>"; };
|
||||||
B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldOptionalType.swift; sourceTree = "<group>"; };
|
B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldOptionalType.swift; sourceTree = "<group>"; };
|
||||||
B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Virtual.swift; sourceTree = "<group>"; };
|
B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Virtual.swift; sourceTree = "<group>"; };
|
||||||
|
B56ED34B263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Internals.AppGroupsManager.swift; sourceTree = "<group>"; };
|
||||||
B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestDataTestCase.swift; sourceTree = "<group>"; };
|
B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestDataTestCase.swift; sourceTree = "<group>"; };
|
||||||
B57D27C11D0BC20100539C58 /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = "<group>"; };
|
B57D27C11D0BC20100539C58 /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = "<group>"; };
|
||||||
B57E6FA123D302FA000FD031 /* Field.Relationship.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Relationship.swift; sourceTree = "<group>"; };
|
B57E6FA123D302FA000FD031 /* Field.Relationship.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Relationship.swift; sourceTree = "<group>"; };
|
||||||
@@ -1973,6 +1978,7 @@
|
|||||||
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */,
|
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */,
|
||||||
B5DE522A230BD7CC00A22534 /* Internals.swift */,
|
B5DE522A230BD7CC00A22534 /* Internals.swift */,
|
||||||
B50C3F0223D1B01C00B29880 /* Internals.AnyFieldCoder.swift */,
|
B50C3F0223D1B01C00B29880 /* Internals.AnyFieldCoder.swift */,
|
||||||
|
B56ED34B263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift */,
|
||||||
B5C976E61C6E3A5900B1AF90 /* Internals.CoreStoreFetchedResultsController.swift */,
|
B5C976E61C6E3A5900B1AF90 /* Internals.CoreStoreFetchedResultsController.swift */,
|
||||||
B5474D142227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift */,
|
B5474D142227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift */,
|
||||||
B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */,
|
B5BF7FAC234C41E90070E741 /* Internals.DiffableDataSourceSnapshot.swift */,
|
||||||
@@ -2391,6 +2397,7 @@
|
|||||||
B56923F01EB827F6007C4DC9 /* XcodeSchemaMappingProvider.swift in Sources */,
|
B56923F01EB827F6007C4DC9 /* XcodeSchemaMappingProvider.swift in Sources */,
|
||||||
B5E84F121AFF847B0064E85B /* OrderBy.swift in Sources */,
|
B5E84F121AFF847B0064E85B /* OrderBy.swift in Sources */,
|
||||||
B5635D142356C39500B80E6B /* DiffableDataSource.CollectionViewAdapter-UIKit.swift in Sources */,
|
B5635D142356C39500B80E6B /* DiffableDataSource.CollectionViewAdapter-UIKit.swift in Sources */,
|
||||||
|
B56ED34C263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift in Sources */,
|
||||||
B5E84F361AFF85470064E85B /* NSManagedObjectContext+Setup.swift in Sources */,
|
B5E84F361AFF85470064E85B /* NSManagedObjectContext+Setup.swift in Sources */,
|
||||||
B50E175223517C6B004F033C /* Internals.DiffableDataUIDispatcher.Changeset.swift in Sources */,
|
B50E175223517C6B004F033C /* Internals.DiffableDataUIDispatcher.Changeset.swift in Sources */,
|
||||||
B5E84EE71AFF84610064E85B /* CoreStore+Logging.swift in Sources */,
|
B5E84EE71AFF84610064E85B /* CoreStore+Logging.swift in Sources */,
|
||||||
@@ -2644,6 +2651,7 @@
|
|||||||
B546F9741C9C553300D5AC55 /* SetupResult.swift in Sources */,
|
B546F9741C9C553300D5AC55 /* SetupResult.swift in Sources */,
|
||||||
B5831F4022126FEC00D8604C /* KeyPathGenericBindings.swift in Sources */,
|
B5831F4022126FEC00D8604C /* KeyPathGenericBindings.swift in Sources */,
|
||||||
B53CA9A31EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
B53CA9A31EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
||||||
|
B56ED34D263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift in Sources */,
|
||||||
82BA18DD1C4BBE1400A0916E /* NSFetchedResultsController+Convenience.swift in Sources */,
|
82BA18DD1C4BBE1400A0916E /* NSFetchedResultsController+Convenience.swift in Sources */,
|
||||||
B5831F432212700400D8604C /* Where.Expression.swift in Sources */,
|
B5831F432212700400D8604C /* Where.Expression.swift in Sources */,
|
||||||
B51260941E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
|
B51260941E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
|
||||||
@@ -2897,6 +2905,7 @@
|
|||||||
B5E1B5AC1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
B5E1B5AC1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
||||||
B52DD1961BE1F92500949AFE /* DataStack.swift in Sources */,
|
B52DD1961BE1F92500949AFE /* DataStack.swift in Sources */,
|
||||||
B5ECDBFD1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
|
B5ECDBFD1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
|
||||||
|
B56ED34F263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift in Sources */,
|
||||||
B52DD1BD1BE1F94300949AFE /* NSManagedObject+Convenience.swift in Sources */,
|
B52DD1BD1BE1F94300949AFE /* NSManagedObject+Convenience.swift in Sources */,
|
||||||
B5831F4222126FED00D8604C /* KeyPathGenericBindings.swift in Sources */,
|
B5831F4222126FED00D8604C /* KeyPathGenericBindings.swift in Sources */,
|
||||||
B53CA9A51EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
B53CA9A51EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
||||||
@@ -3150,6 +3159,7 @@
|
|||||||
B5831F4122126FEC00D8604C /* KeyPathGenericBindings.swift in Sources */,
|
B5831F4122126FEC00D8604C /* KeyPathGenericBindings.swift in Sources */,
|
||||||
B53CA9A41EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
B53CA9A41EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
||||||
B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */,
|
B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */,
|
||||||
|
B56ED34E263FF64B00ACCCB8 /* Internals.AppGroupsManager.swift in Sources */,
|
||||||
B5FE4DA91C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
B5FE4DA91C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
||||||
B5831F442212700500D8604C /* Where.Expression.swift in Sources */,
|
B5831F442212700500D8604C /* Where.Expression.swift in Sources */,
|
||||||
B50C3F0023D1AB1400B29880 /* FieldCoders.Plist.swift in Sources */,
|
B50C3F0023D1AB1400B29880 /* FieldCoders.Plist.swift in Sources */,
|
||||||
|
|||||||
@@ -92,5 +92,3 @@ dataStack.addStorage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -429,7 +429,10 @@ public /*abstract*/ class BaseDataTransaction {
|
|||||||
|
|
||||||
internal let context: NSManagedObjectContext
|
internal let context: NSManagedObjectContext
|
||||||
internal let transactionQueue: DispatchQueue
|
internal let transactionQueue: DispatchQueue
|
||||||
internal let childTransactionQueue = DispatchQueue.serial("com.corestore.datastack.childTransactionQueue", qos: .utility)
|
internal let childTransactionQueue = DispatchQueue.serial(
|
||||||
|
Internals.libReverseDomain("BaseDataTransaction.childTransactionQueue"),
|
||||||
|
qos: .utility
|
||||||
|
)
|
||||||
internal let supportsUndo: Bool
|
internal let supportsUndo: Bool
|
||||||
internal let bypassesQueueing: Bool
|
internal let bypassesQueueing: Bool
|
||||||
internal var isCommitted = false
|
internal var isCommitted = false
|
||||||
|
|||||||
@@ -69,7 +69,10 @@ public enum CoreStoreDefaults {
|
|||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private static let defaultStackBarrierQueue = DispatchQueue.concurrent("com.coreStore.defaultStackBarrierQueue", qos: .userInteractive)
|
private static let defaultStackBarrierQueue = DispatchQueue.concurrent(
|
||||||
|
Internals.libReverseDomain("CoreStoreDefaults.defaultStackBarrierQueue"),
|
||||||
|
qos: .userInteractive
|
||||||
|
)
|
||||||
|
|
||||||
private static var defaultStackInstance: DataStack?
|
private static var defaultStackInstance: DataStack?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ public enum CoreStoreError: Error, CustomNSError, Hashable {
|
|||||||
The `NSError` error domain string for `CSError`.
|
The `NSError` error domain string for `CSError`.
|
||||||
*/
|
*/
|
||||||
@nonobjc
|
@nonobjc
|
||||||
public let CoreStoreErrorDomain = "com.corestore.error"
|
public let CoreStoreErrorDomain = Internals.libReverseDomain("error")
|
||||||
|
|
||||||
|
|
||||||
// MARK: - CoreStoreErrorCode
|
// MARK: - CoreStoreErrorCode
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ import Foundation
|
|||||||
|
|
||||||
private enum Static {
|
private enum Static {
|
||||||
|
|
||||||
static let queue = DispatchQueue.concurrent("com.coreStore.coreStoreManagerObjectBarrierQueue", qos: .userInteractive)
|
static let queue = DispatchQueue.concurrent(
|
||||||
|
Internals.libReverseDomain("CoreStoreManagerObject.barrierQueue"),
|
||||||
|
qos: .userInteractive
|
||||||
|
)
|
||||||
static var cache: [ObjectIdentifier: [KeyPathString: Set<KeyPathString>]] = [:]
|
static var cache: [ObjectIdentifier: [KeyPathString: Set<KeyPathString>]] = [:]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,7 +254,10 @@ public final class CoreStoreSchema: DynamicSchema {
|
|||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private static let barrierQueue = DispatchQueue.concurrent("com.coreStore.coreStoreDataModelBarrierQueue", qos: .userInteractive)
|
private static let barrierQueue = DispatchQueue.concurrent(
|
||||||
|
Internals.libReverseDomain("CoreStoreSchema.barrierQueue"),
|
||||||
|
qos: .userInteractive
|
||||||
|
)
|
||||||
|
|
||||||
private let allEntities: Set<DynamicEntity>
|
private let allEntities: Set<DynamicEntity>
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,24 @@ extension DataStack {
|
|||||||
|
|
||||||
return self.coordinator.performSynchronously {
|
return self.coordinator.performSynchronously {
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
try storage.cs_willBeAdded(toDataStack: self)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
|
||||||
|
let storeError = CoreStoreError(error)
|
||||||
|
Internals.log(
|
||||||
|
storeError,
|
||||||
|
"Failed to preparing to add \(Internals.typeName(storage)) at \"\(fileURL)\"."
|
||||||
|
)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
|
||||||
|
completion(.failure(storeError))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if let _ = self.persistentStoreForStorage(storage) {
|
if let _ = self.persistentStoreForStorage(storage) {
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
@@ -562,7 +580,7 @@ extension DataStack {
|
|||||||
do {
|
do {
|
||||||
|
|
||||||
let timerQueue = DispatchQueue(
|
let timerQueue = DispatchQueue(
|
||||||
label: "DataStack.lightweightMigration.timerQueue",
|
label: Internals.libReverseDomain("DataStack.lightweightMigration.timerQueue"),
|
||||||
qos: .utility,
|
qos: .utility,
|
||||||
attributes: []
|
attributes: []
|
||||||
)
|
)
|
||||||
@@ -614,7 +632,7 @@ extension DataStack {
|
|||||||
}
|
}
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
let temporaryDirectoryURL = fileManager.temporaryDirectory
|
let temporaryDirectoryURL = fileManager.temporaryDirectory
|
||||||
.appendingPathComponent(Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack")
|
.appendingPathComponent(Internals.bundleTag())
|
||||||
.appendingPathComponent(ProcessInfo().globallyUniqueString)
|
.appendingPathComponent(ProcessInfo().globallyUniqueString)
|
||||||
|
|
||||||
try! fileManager.createDirectory(
|
try! fileManager.createDirectory(
|
||||||
|
|||||||
@@ -148,7 +148,10 @@ extension DataStack {
|
|||||||
|
|
||||||
return UnsafeDataTransaction(
|
return UnsafeDataTransaction(
|
||||||
mainContext: self.rootSavingContext,
|
mainContext: self.rootSavingContext,
|
||||||
queue: DispatchQueue.serial("com.coreStore.dataStack.unsafeTransactionQueue", qos: .userInitiated),
|
queue: DispatchQueue.serial(
|
||||||
|
Internals.libReverseDomain("UnsafeDataTransaction.queue"),
|
||||||
|
qos: .userInitiated
|
||||||
|
),
|
||||||
supportsUndo: supportsUndo
|
supportsUndo: supportsUndo
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -440,15 +440,24 @@ public final class DataStack: Equatable {
|
|||||||
internal let rootSavingContext: NSManagedObjectContext
|
internal let rootSavingContext: NSManagedObjectContext
|
||||||
internal let mainContext: NSManagedObjectContext
|
internal let mainContext: NSManagedObjectContext
|
||||||
internal let schemaHistory: SchemaHistory
|
internal let schemaHistory: SchemaHistory
|
||||||
internal let childTransactionQueue = DispatchQueue.serial("com.coreStore.dataStack.childTransactionQueue", qos: .utility)
|
internal let childTransactionQueue = DispatchQueue.serial(
|
||||||
internal let storeMetadataUpdateQueue = DispatchQueue.concurrent("com.coreStore.persistentStoreBarrierQueue", qos: .userInteractive)
|
Internals.libReverseDomain("DataStack.childTransactionQueue"),
|
||||||
|
qos: .utility
|
||||||
|
)
|
||||||
|
internal let storeMetadataUpdateQueue = DispatchQueue.concurrent(
|
||||||
|
Internals.libReverseDomain("DataStack.persistentStoreBarrierQueue"),
|
||||||
|
qos: .userInteractive
|
||||||
|
)
|
||||||
internal let migrationQueue: OperationQueue = Internals.with {
|
internal let migrationQueue: OperationQueue = Internals.with {
|
||||||
|
|
||||||
let migrationQueue = OperationQueue()
|
let migrationQueue = OperationQueue()
|
||||||
migrationQueue.maxConcurrentOperationCount = 1
|
migrationQueue.maxConcurrentOperationCount = 1
|
||||||
migrationQueue.name = "com.coreStore.migrationOperationQueue"
|
migrationQueue.name = Internals.libReverseDomain("DataStack.migrationOperationQueue")
|
||||||
migrationQueue.qualityOfService = .utility
|
migrationQueue.qualityOfService = .utility
|
||||||
migrationQueue.underlyingQueue = DispatchQueue.serial("com.coreStore.migrationQueue", qos: .userInitiated)
|
migrationQueue.underlyingQueue = DispatchQueue.serial(
|
||||||
|
Internals.libReverseDomain("DataStack.migrationQueue"),
|
||||||
|
qos: .userInitiated
|
||||||
|
)
|
||||||
return migrationQueue
|
return migrationQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,7 +539,7 @@ public final class DataStack: Equatable {
|
|||||||
self.finalConfigurationsByEntityIdentifier[entityIdentifier]?.insert(configurationName)
|
self.finalConfigurationsByEntityIdentifier[entityIdentifier]?.insert(configurationName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
storage.cs_didAddToDataStack(self)
|
try storage.cs_didAddToDataStack(self)
|
||||||
return persistentStore
|
return persistentStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public final class InMemoryStore: StorageInterface {
|
|||||||
/**
|
/**
|
||||||
Do not call directly. Used by the `DataStack` internally.
|
Do not call directly. Used by the `DataStack` internally.
|
||||||
*/
|
*/
|
||||||
public func cs_didAddToDataStack(_ dataStack: DataStack) {
|
public func cs_didAddToDataStack(_ dataStack: DataStack) throws {
|
||||||
|
|
||||||
self.dataStack = dataStack
|
self.dataStack = dataStack
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ public final class InMemoryStore: StorageInterface {
|
|||||||
/**
|
/**
|
||||||
Do not call directly. Used by the `DataStack` internally.
|
Do not call directly. Used by the `DataStack` internally.
|
||||||
*/
|
*/
|
||||||
public func cs_didRemoveFromDataStack(_ dataStack: DataStack) {
|
public func cs_didRemoveFromDataStack(_ dataStack: DataStack) throws {
|
||||||
|
|
||||||
self.dataStack = nil
|
self.dataStack = nil
|
||||||
}
|
}
|
||||||
|
|||||||
406
Sources/Internals.AppGroupsManager.swift
Normal file
406
Sources/Internals.AppGroupsManager.swift
Normal file
@@ -0,0 +1,406 @@
|
|||||||
|
//
|
||||||
|
// Internals.AppGroupsManager.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2020 John Rommel Estropia
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Internals
|
||||||
|
|
||||||
|
extension Internals {
|
||||||
|
|
||||||
|
// MARK: - AppGroupsManager
|
||||||
|
|
||||||
|
internal enum AppGroupsManager {
|
||||||
|
|
||||||
|
// MARK: Internal
|
||||||
|
|
||||||
|
internal typealias BundleID = String
|
||||||
|
|
||||||
|
internal typealias StoreID = UUID
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
internal static func register(
|
||||||
|
appGroupIdentifier: String,
|
||||||
|
subdirectory: String?,
|
||||||
|
fileName: String
|
||||||
|
) throws -> StoreID {
|
||||||
|
|
||||||
|
let bundleID = self.bundleID()
|
||||||
|
let indexMetadataURL = self.indexMetadataURL(
|
||||||
|
appGroupIdentifier: appGroupIdentifier
|
||||||
|
)
|
||||||
|
return try self.metadata(
|
||||||
|
forWritingAt: indexMetadataURL,
|
||||||
|
initializer: IndexMetadata.init,
|
||||||
|
{ metadata in
|
||||||
|
|
||||||
|
return metadata.fetchOrCreateStoreID(
|
||||||
|
bundleID: bundleID,
|
||||||
|
subdirectory: subdirectory,
|
||||||
|
fileName: fileName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static func existingToken(
|
||||||
|
appGroupIdentifier: String,
|
||||||
|
subdirectory: String,
|
||||||
|
fileName: String
|
||||||
|
) throws -> NSPersistentHistoryToken? {
|
||||||
|
|
||||||
|
let bundleID = self.bundleID()
|
||||||
|
let indexMetadataURL = self.indexMetadataURL(
|
||||||
|
appGroupIdentifier: appGroupIdentifier
|
||||||
|
)
|
||||||
|
guard
|
||||||
|
let storeID = try self.metadata(
|
||||||
|
forReadingAt: indexMetadataURL,
|
||||||
|
{ (metadata: IndexMetadata) in
|
||||||
|
|
||||||
|
return metadata.fetchStoreID(
|
||||||
|
bundleID: bundleID,
|
||||||
|
subdirectory: subdirectory,
|
||||||
|
fileName: fileName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let storageMetadataURL = self.storageMetadataURL(
|
||||||
|
appGroupIdentifier: appGroupIdentifier,
|
||||||
|
bundleID: bundleID,
|
||||||
|
storeID: storeID
|
||||||
|
)
|
||||||
|
return try self.metadata(
|
||||||
|
forReadingAt: storageMetadataURL,
|
||||||
|
{ (metadata: StorageMetadata) in
|
||||||
|
|
||||||
|
return metadata.persistentHistoryToken
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static func setExistingToken(
|
||||||
|
_ newToken: NSPersistentHistoryToken,
|
||||||
|
appGroupIdentifier: String,
|
||||||
|
subdirectory: String,
|
||||||
|
fileName: String
|
||||||
|
) throws {
|
||||||
|
|
||||||
|
let bundleID = self.bundleID()
|
||||||
|
let indexMetadataURL = self.indexMetadataURL(
|
||||||
|
appGroupIdentifier: appGroupIdentifier
|
||||||
|
)
|
||||||
|
guard
|
||||||
|
let storeID = try self.metadata(
|
||||||
|
forReadingAt: indexMetadataURL,
|
||||||
|
{ (metadata: IndexMetadata) in
|
||||||
|
|
||||||
|
return metadata.fetchStoreID(
|
||||||
|
bundleID: bundleID,
|
||||||
|
subdirectory: subdirectory,
|
||||||
|
fileName: fileName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let storageMetadataURL = self.storageMetadataURL(
|
||||||
|
appGroupIdentifier: appGroupIdentifier,
|
||||||
|
bundleID: bundleID,
|
||||||
|
storeID: storeID
|
||||||
|
)
|
||||||
|
try self.metadata(
|
||||||
|
forWritingAt: storageMetadataURL,
|
||||||
|
initializer: StorageMetadata.init,
|
||||||
|
{ metadata in
|
||||||
|
|
||||||
|
metadata.persistentHistoryToken = newToken
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private static func appGroupContainerURL(
|
||||||
|
appGroupIdentifier: String
|
||||||
|
) -> URL {
|
||||||
|
|
||||||
|
guard let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) else {
|
||||||
|
|
||||||
|
Internals.abort("Failed to join app group named \"\(appGroupIdentifier)\". Make sure that this app is registered into this app group through the entitlements file.")
|
||||||
|
}
|
||||||
|
return containerURL
|
||||||
|
.appendingPathComponent(Internals.libReverseDomain(), isDirectory: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func indexMetadataURL(
|
||||||
|
appGroupIdentifier: String
|
||||||
|
) -> URL {
|
||||||
|
|
||||||
|
return self.appGroupContainerURL(appGroupIdentifier: appGroupIdentifier)
|
||||||
|
.appendingPathComponent("index.meta", isDirectory: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func storageMetadataURL(
|
||||||
|
appGroupIdentifier: String,
|
||||||
|
bundleID: BundleID,
|
||||||
|
storeID: StoreID
|
||||||
|
) -> URL {
|
||||||
|
|
||||||
|
return self
|
||||||
|
.appGroupContainerURL(appGroupIdentifier: appGroupIdentifier)
|
||||||
|
.appendingPathComponent(bundleID, isDirectory: true)
|
||||||
|
.appendingPathComponent(storeID.uuidString, isDirectory: false)
|
||||||
|
.appendingPathExtension("meta")
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func metadata<Metadata: Codable, Result>(
|
||||||
|
forReadingAt url: URL,
|
||||||
|
_ task: @escaping (Metadata) -> Result?
|
||||||
|
) throws -> Result? {
|
||||||
|
|
||||||
|
let fileCoordinator = NSFileCoordinator()
|
||||||
|
var fileCoordinatorError: NSError?
|
||||||
|
var accessorError: Error?
|
||||||
|
var result: Result?
|
||||||
|
fileCoordinator.coordinate(
|
||||||
|
readingItemAt: url,
|
||||||
|
options: .withoutChanges,
|
||||||
|
error: &fileCoordinatorError,
|
||||||
|
byAccessor: { url in
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
guard let metadata: Metadata = try self.loadMetadata(lockedURL: url) else {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result = task(metadata)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
|
||||||
|
accessorError = error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if let fileCoordinatorError = fileCoordinatorError {
|
||||||
|
|
||||||
|
throw CoreStoreError(fileCoordinatorError)
|
||||||
|
}
|
||||||
|
else if let accessorError = accessorError {
|
||||||
|
|
||||||
|
throw CoreStoreError(accessorError)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func metadata<Metadata: Codable, Result>(
|
||||||
|
forWritingAt url: URL,
|
||||||
|
initializer: @escaping () -> Metadata,
|
||||||
|
_ task: @escaping (inout Metadata) -> Result
|
||||||
|
) throws -> Result {
|
||||||
|
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
try? fileManager.createDirectory(
|
||||||
|
at: url.deletingLastPathComponent(),
|
||||||
|
withIntermediateDirectories: true,
|
||||||
|
attributes: nil
|
||||||
|
)
|
||||||
|
|
||||||
|
let fileCoordinator = NSFileCoordinator()
|
||||||
|
var fileCoordinatorError: NSError?
|
||||||
|
var accessorError: Error?
|
||||||
|
var result: Result?
|
||||||
|
fileCoordinator.coordinate(
|
||||||
|
writingItemAt: url,
|
||||||
|
options: .forReplacing,
|
||||||
|
error: &fileCoordinatorError,
|
||||||
|
byAccessor: { url in
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
var metadata: Metadata = try self.loadMetadata(lockedURL: url)
|
||||||
|
?? initializer()
|
||||||
|
result = task(&metadata)
|
||||||
|
try self.saveMetadata(metadata, lockedURL: url)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
|
||||||
|
accessorError = error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if let fileCoordinatorError = fileCoordinatorError {
|
||||||
|
|
||||||
|
throw CoreStoreError(fileCoordinatorError)
|
||||||
|
}
|
||||||
|
else if let accessorError = accessorError {
|
||||||
|
|
||||||
|
throw CoreStoreError(accessorError)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
return result!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func bundleID() -> String {
|
||||||
|
|
||||||
|
guard let bundleID = Bundle.main.bundleIdentifier else {
|
||||||
|
|
||||||
|
Internals.abort("App Group containers can only be used for bundled projects.")
|
||||||
|
}
|
||||||
|
return bundleID
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func loadMetadata<Metadata: Codable>(
|
||||||
|
lockedURL url: URL
|
||||||
|
) throws -> Metadata? {
|
||||||
|
|
||||||
|
let decoder = PropertyListDecoder()
|
||||||
|
guard let data = try? Data(contentsOf: url) else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return try decoder.decode(Metadata.self, from: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func saveMetadata<Metadata: Codable>(
|
||||||
|
_ metadata: Metadata,
|
||||||
|
lockedURL url: URL
|
||||||
|
) throws {
|
||||||
|
|
||||||
|
let encoder = PropertyListEncoder()
|
||||||
|
let data = try encoder.encode(metadata)
|
||||||
|
try data.write(to: url, options: .atomic)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - IndexMetadata
|
||||||
|
|
||||||
|
fileprivate struct IndexMetadata: Codable {
|
||||||
|
|
||||||
|
// MARK: FilePrivate
|
||||||
|
|
||||||
|
fileprivate func fetchStoreID(
|
||||||
|
bundleID: BundleID,
|
||||||
|
subdirectory: String?,
|
||||||
|
fileName: String
|
||||||
|
) -> StoreID? {
|
||||||
|
|
||||||
|
let fileTag = Self.createFileTag(subdirectory: subdirectory, fileName: fileName)
|
||||||
|
return self.contents[bundleID, default: [:]][fileTag]
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate mutating func fetchOrCreateStoreID(
|
||||||
|
bundleID: BundleID,
|
||||||
|
subdirectory: String?,
|
||||||
|
fileName: String
|
||||||
|
) -> StoreID {
|
||||||
|
|
||||||
|
let fileTag = Self.createFileTag(subdirectory: subdirectory, fileName: fileName)
|
||||||
|
return self.contents[bundleID, default: [:]][fileTag, default: UUID()]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Codable
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
||||||
|
case contents = "contents"
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private typealias FileTag = String
|
||||||
|
|
||||||
|
private var contents: [BundleID: [FileTag: UUID]] = [:]
|
||||||
|
|
||||||
|
private static func createFileTag(subdirectory: String?, fileName: String) -> FileTag {
|
||||||
|
|
||||||
|
guard let subdirectory = subdirectory else {
|
||||||
|
|
||||||
|
return fileName
|
||||||
|
}
|
||||||
|
return (subdirectory as NSString).appendingPathComponent(fileName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - StorageMetadata
|
||||||
|
|
||||||
|
fileprivate struct StorageMetadata: Codable {
|
||||||
|
|
||||||
|
// MARK: FilePrivate
|
||||||
|
|
||||||
|
fileprivate var persistentHistoryToken: NSPersistentHistoryToken? {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
return self.persistentHistoryTokenData.flatMap {
|
||||||
|
|
||||||
|
return try! NSKeyedUnarchiver.unarchivedObject(
|
||||||
|
ofClass: NSPersistentHistoryToken.self,
|
||||||
|
from: $0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
self.persistentHistoryTokenData = newValue.map {
|
||||||
|
|
||||||
|
return try! NSKeyedArchiver.archivedData(
|
||||||
|
withRootObject: $0,
|
||||||
|
requiringSecureCoding: true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Codable
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
||||||
|
case persistentHistoryTokenData = "persistent_history_token_data"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private var persistentHistoryTokenData: Data?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -30,10 +30,30 @@ import Foundation
|
|||||||
@usableFromInline
|
@usableFromInline
|
||||||
internal enum Internals {
|
internal enum Internals {
|
||||||
|
|
||||||
// MARK: Associated Objects
|
// MARK: Namespacing
|
||||||
|
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
|
internal static func libReverseDomain() -> String {
|
||||||
|
|
||||||
|
return "com.johnestropia.corestore"
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
|
internal static func libReverseDomain(_ suffix: String) -> String {
|
||||||
|
|
||||||
|
return "com.johnestropia.corestore.\(suffix)"
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
|
internal static func bundleTag() -> String {
|
||||||
|
|
||||||
|
return Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack"
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Associated Objects
|
||||||
|
|
||||||
/// type(of:) doesn't return the dynamic type anymore, use this to guarantee correct dispatch of class methods
|
/// type(of:) doesn't return the dynamic type anymore, use this to guarantee correct dispatch of class methods
|
||||||
|
@inline(__always)
|
||||||
internal static func dynamicObjectType<T: AnyObject>(of instance: T) -> T.Type {
|
internal static func dynamicObjectType<T: AnyObject>(of instance: T) -> T.Type {
|
||||||
|
|
||||||
return object_getClass(instance) as! T.Type
|
return object_getClass(instance) as! T.Type
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ extension NSManagedObjectContext {
|
|||||||
context.persistentStoreCoordinator = coordinator
|
context.persistentStoreCoordinator = coordinator
|
||||||
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
||||||
context.undoManager = nil
|
context.undoManager = nil
|
||||||
context.setupForCoreStoreWithContextName("com.corestore.rootcontext")
|
context.setupForCoreStoreWithContextName(Internals.libReverseDomain("rootContext"))
|
||||||
|
|
||||||
#if os(iOS) || os(macOS)
|
#if os(iOS) || os(macOS)
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ extension NSManagedObjectContext {
|
|||||||
context.parent = rootContext
|
context.parent = rootContext
|
||||||
context.mergePolicy = NSRollbackMergePolicy
|
context.mergePolicy = NSRollbackMergePolicy
|
||||||
context.undoManager = nil
|
context.undoManager = nil
|
||||||
context.setupForCoreStoreWithContextName("com.corestore.maincontext")
|
context.setupForCoreStoreWithContextName(Internals.libReverseDomain("mainContext"))
|
||||||
context.observerForDidSaveNotification = Internals.NotificationObserver(
|
context.observerForDidSaveNotification = Internals.NotificationObserver(
|
||||||
notificationName: NSNotification.Name.NSManagedObjectContextDidSave,
|
notificationName: NSNotification.Name.NSManagedObjectContextDidSave,
|
||||||
object: rootContext,
|
object: rootContext,
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ extension NSManagedObjectContext {
|
|||||||
let context = NSManagedObjectContext(concurrencyType: concurrencyType)
|
let context = NSManagedObjectContext(concurrencyType: concurrencyType)
|
||||||
context.parent = self
|
context.parent = self
|
||||||
context.parentStack = self.parentStack
|
context.parentStack = self.parentStack
|
||||||
context.setupForCoreStoreWithContextName("com.corestore.temporarycontext")
|
context.setupForCoreStoreWithContextName(Internals.libReverseDomain("temporaryContext"))
|
||||||
context.shouldCascadeSavesToParent = (self.parentStack?.rootSavingContext == self)
|
context.shouldCascadeSavesToParent = (self.parentStack?.rootSavingContext == self)
|
||||||
context.retainsRegisteredObjects = true
|
context.retainsRegisteredObjects = true
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public final class SQLiteStore: LocalStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Initializes an SQLite store interface with a device-wide shared persistent store using a registered App Group Identifier. This store does not use remote persistent history tracking, and should be used only in the context of App-Extension shared stores.
|
Initializes an SQLite store interface with a device-wide shared persistent store using a registered App Group Identifier. This store does not use remote persistent history tracking, and should be used only in the context of App Groups and App Extensions.
|
||||||
|
|
||||||
- Important: The app will be force-terminated if the `appGroupIdentifier` is not registered for the app.
|
- Important: The app will be force-terminated if the `appGroupIdentifier` is not registered for the app.
|
||||||
- parameter appGroupIdentifier: the App Group identifier registered for this application. The app will be force-terminated if this identifier is not registered for the app.
|
- parameter appGroupIdentifier: the App Group identifier registered for this application. The app will be force-terminated if this identifier is not registered for the app.
|
||||||
@@ -200,20 +200,51 @@ public final class SQLiteStore: LocalStorage {
|
|||||||
public let configuration: ModelConfiguration
|
public let configuration: ModelConfiguration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The options dictionary for the `NSPersistentStore`. For `SQLiteStore`s, this is always set to
|
The options dictionary for the `NSPersistentStore`.
|
||||||
```
|
|
||||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]]
|
|
||||||
```
|
|
||||||
*/
|
*/
|
||||||
public let storeOptions: [AnyHashable: Any]? = [
|
public var storeOptions: [AnyHashable: Any]? {
|
||||||
NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
|
||||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true
|
var options: [AnyHashable: Any] = [
|
||||||
]
|
NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
||||||
|
NSBinaryStoreInsecureDecodingCompatibilityOption: true
|
||||||
|
]
|
||||||
|
switch self.container {
|
||||||
|
|
||||||
|
case .appGroup:
|
||||||
|
options[NSPersistentHistoryTrackingKey] = true
|
||||||
|
if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
|
||||||
|
|
||||||
|
options[NSPersistentStoreRemoteChangeNotificationPostOptionKey] = true
|
||||||
|
}
|
||||||
|
#warning("TODO: handle remote changes for iOS 11 & 12")
|
||||||
|
|
||||||
|
case .custom,
|
||||||
|
.default,
|
||||||
|
.legacy:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Do not call directly. Used by the `DataStack` internally.
|
Do not call directly. Used by the `DataStack` internally.
|
||||||
*/
|
*/
|
||||||
public func cs_didAddToDataStack(_ dataStack: DataStack) {
|
public func cs_didAddToDataStack(_ dataStack: DataStack) throws {
|
||||||
|
|
||||||
|
switch self.container {
|
||||||
|
|
||||||
|
case .appGroup(let appGroupIdentifier, let subdirectory, let fileName):
|
||||||
|
try Internals.AppGroupsManager.register(
|
||||||
|
appGroupIdentifier: appGroupIdentifier,
|
||||||
|
subdirectory: subdirectory,
|
||||||
|
fileName: fileName
|
||||||
|
)
|
||||||
|
|
||||||
|
case .custom,
|
||||||
|
.default,
|
||||||
|
.legacy:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
self.dataStack = dataStack
|
self.dataStack = dataStack
|
||||||
}
|
}
|
||||||
@@ -297,7 +328,7 @@ public final class SQLiteStore: LocalStorage {
|
|||||||
do {
|
do {
|
||||||
|
|
||||||
let trashURL = URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!)
|
let trashURL = URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!)
|
||||||
.appendingPathComponent(Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack", isDirectory: true)
|
.appendingPathComponent(Internals.bundleTag(), isDirectory: true)
|
||||||
.appendingPathComponent("trash", isDirectory: true)
|
.appendingPathComponent("trash", isDirectory: true)
|
||||||
try fileManager.createDirectory(
|
try fileManager.createDirectory(
|
||||||
at: trashURL,
|
at: trashURL,
|
||||||
@@ -353,6 +384,8 @@ public final class SQLiteStore: LocalStorage {
|
|||||||
|
|
||||||
// MARK: Internal
|
// MARK: Internal
|
||||||
|
|
||||||
|
internal let container: Container
|
||||||
|
|
||||||
internal static let defaultRootDirectory: URL = Internals.with {
|
internal static let defaultRootDirectory: URL = Internals.with {
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
@@ -366,7 +399,7 @@ public final class SQLiteStore: LocalStorage {
|
|||||||
in: .userDomainMask).first!
|
in: .userDomainMask).first!
|
||||||
|
|
||||||
return defaultSystemDirectory.appendingPathComponent(
|
return defaultSystemDirectory.appendingPathComponent(
|
||||||
Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack",
|
Internals.bundleTag(),
|
||||||
isDirectory: true
|
isDirectory: true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -404,7 +437,6 @@ public final class SQLiteStore: LocalStorage {
|
|||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private weak var dataStack: DataStack?
|
private weak var dataStack: DataStack?
|
||||||
private let container: Container
|
|
||||||
|
|
||||||
private init(
|
private init(
|
||||||
container: Container,
|
container: Container,
|
||||||
|
|||||||
@@ -54,12 +54,12 @@ public protocol StorageInterface: AnyObject {
|
|||||||
/**
|
/**
|
||||||
Do not call directly. Used by the `DataStack` internally.
|
Do not call directly. Used by the `DataStack` internally.
|
||||||
*/
|
*/
|
||||||
func cs_didAddToDataStack(_ dataStack: DataStack)
|
func cs_didAddToDataStack(_ dataStack: DataStack) throws
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Do not call directly. Used by the `DataStack` internally.
|
Do not call directly. Used by the `DataStack` internally.
|
||||||
*/
|
*/
|
||||||
func cs_didRemoveFromDataStack(_ dataStack: DataStack)
|
func cs_didRemoveFromDataStack(_ dataStack: DataStack) throws
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user