mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-27 11:51:31 +01:00
WIP: object concurrency debugging utilities
This commit is contained in:
@@ -197,6 +197,10 @@
|
|||||||
B52DD1C91BE1F94600949AFE /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; };
|
B52DD1C91BE1F94600949AFE /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; };
|
||||||
B52DD1CA1BE1F94600949AFE /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; };
|
B52DD1CA1BE1F94600949AFE /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; };
|
||||||
B52DD1CB1BE1F94600949AFE /* WeakObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F2D1AFF849C0064E85B /* WeakObject.swift */; };
|
B52DD1CB1BE1F94600949AFE /* WeakObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F2D1AFF849C0064E85B /* WeakObject.swift */; };
|
||||||
|
B52FD3AA1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||||
|
B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||||
|
B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||||
|
B52FD3AD1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||||
B533C4DB1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
B533C4DB1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
||||||
B533C4DC1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
B533C4DC1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
||||||
B533C4DD1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
B533C4DD1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
||||||
@@ -619,6 +623,7 @@
|
|||||||
B529C2031CA4A2DB007E7EBD /* CSSaveResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSaveResult.swift; sourceTree = "<group>"; };
|
B529C2031CA4A2DB007E7EBD /* CSSaveResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSaveResult.swift; sourceTree = "<group>"; };
|
||||||
B52DD1741BE1F8CC00949AFE /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
B52DD1741BE1F8CC00949AFE /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B52DD17D1BE1F8CC00949AFE /* CoreStoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreStoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
B52DD17D1BE1F8CC00949AFE /* CoreStoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreStoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Logging.swift"; sourceTree = "<group>"; };
|
||||||
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+CoreStore.swift"; sourceTree = "<group>"; };
|
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+CoreStore.swift"; sourceTree = "<group>"; };
|
||||||
B538BA701D15B3E30003A766 /* CoreStoreBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoreStoreBridge.m; sourceTree = "<group>"; };
|
B538BA701D15B3E30003A766 /* CoreStoreBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoreStoreBridge.m; sourceTree = "<group>"; };
|
||||||
B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSMigrationResult.swift; sourceTree = "<group>"; };
|
B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSMigrationResult.swift; sourceTree = "<group>"; };
|
||||||
@@ -1210,6 +1215,7 @@
|
|||||||
B5FAD6AB1B51285300714891 /* MigrationManager.swift */,
|
B5FAD6AB1B51285300714891 /* MigrationManager.swift */,
|
||||||
B5E84F2B1AFF849C0064E85B /* NotificationObserver.swift */,
|
B5E84F2B1AFF849C0064E85B /* NotificationObserver.swift */,
|
||||||
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */,
|
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */,
|
||||||
|
B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */,
|
||||||
B5E84F2C1AFF849C0064E85B /* NSManagedObjectContext+CoreStore.swift */,
|
B5E84F2C1AFF849C0064E85B /* NSManagedObjectContext+CoreStore.swift */,
|
||||||
B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */,
|
B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */,
|
||||||
B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */,
|
B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */,
|
||||||
@@ -1558,6 +1564,7 @@
|
|||||||
B5ECDC051CA8138100C7F112 /* CSOrderBy.swift in Sources */,
|
B5ECDC051CA8138100C7F112 /* CSOrderBy.swift in Sources */,
|
||||||
B5E1B5981CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
|
B5E1B5981CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
|
||||||
B5519A5F1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
B5519A5F1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
||||||
|
B52FD3AA1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
|
||||||
B51FE5AB1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
B51FE5AB1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
||||||
B54A6A551BA15F2A007870FD /* FetchedResultsControllerDelegate.swift in Sources */,
|
B54A6A551BA15F2A007870FD /* FetchedResultsControllerDelegate.swift in Sources */,
|
||||||
B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */,
|
B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */,
|
||||||
@@ -1711,6 +1718,7 @@
|
|||||||
B5ECDC071CA8138100C7F112 /* CSOrderBy.swift in Sources */,
|
B5ECDC071CA8138100C7F112 /* CSOrderBy.swift in Sources */,
|
||||||
B5E1B59A1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
|
B5E1B59A1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
|
||||||
B5519A601CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
B5519A601CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
||||||
|
B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
|
||||||
B51FE5AD1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
B51FE5AD1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
||||||
B5FE4DAD1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */,
|
B5FE4DAD1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */,
|
||||||
82BA18C51C4BBD5300A0916E /* ListObserver.swift in Sources */,
|
82BA18C51C4BBD5300A0916E /* ListObserver.swift in Sources */,
|
||||||
@@ -1864,6 +1872,7 @@
|
|||||||
B5ECDC0F1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
|
B5ECDC0F1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
|
||||||
B5ECDC211CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
|
B5ECDC211CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
|
||||||
B52DD1C21BE1F94600949AFE /* MigrationManager.swift in Sources */,
|
B52DD1C21BE1F94600949AFE /* MigrationManager.swift in Sources */,
|
||||||
|
B52FD3AD1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
|
||||||
B5ECDC2D1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
|
B5ECDC2D1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
|
||||||
B5D7A5BA1CA3BF8F005C752B /* CSInto.swift in Sources */,
|
B5D7A5BA1CA3BF8F005C752B /* CSInto.swift in Sources */,
|
||||||
B5A5F26A1CAEC50F004AB9AF /* CSSelect.swift in Sources */,
|
B5A5F26A1CAEC50F004AB9AF /* CSSelect.swift in Sources */,
|
||||||
@@ -2017,6 +2026,7 @@
|
|||||||
B5E1B59B1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
|
B5E1B59B1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
|
||||||
B5519A611CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
B5519A611CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
||||||
B5FE4DAE1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */,
|
B5FE4DAE1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */,
|
||||||
|
B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
|
||||||
B51FE5AE1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
B51FE5AE1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
||||||
B563218C1BD65216006C9394 /* DataStack+Transaction.swift in Sources */,
|
B563218C1BD65216006C9394 /* DataStack+Transaction.swift in Sources */,
|
||||||
B53FBA0E1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */,
|
B53FBA0E1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */,
|
||||||
|
|||||||
@@ -153,6 +153,8 @@ class TestLogger: CoreStoreLogger {
|
|||||||
|
|
||||||
// MARK: CoreStoreLogger
|
// MARK: CoreStoreLogger
|
||||||
|
|
||||||
|
var enableObjectConcurrencyDebugging: Bool = true
|
||||||
|
|
||||||
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||||
|
|
||||||
switch level {
|
switch level {
|
||||||
|
|||||||
240
Sources/Internal/NSManagedObject+Logging.swift
Normal file
240
Sources/Internal/NSManagedObject+Logging.swift
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
//
|
||||||
|
// NSManagedObject+Logging.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2017 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
|
||||||
|
import CoreData
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - NSManagedObject
|
||||||
|
|
||||||
|
internal extension NSManagedObject {
|
||||||
|
|
||||||
|
@nonobjc
|
||||||
|
internal static func cs_swizzleMethodsForLogging() {
|
||||||
|
|
||||||
|
struct Static {
|
||||||
|
|
||||||
|
static let isSwizzled = Static.swizzle()
|
||||||
|
|
||||||
|
private static func swizzle() -> Bool {
|
||||||
|
|
||||||
|
NSManagedObject.cs_swizzle(
|
||||||
|
original: #selector(NSManagedObject.willAccessValue(forKey:)),
|
||||||
|
proxy: #selector(NSManagedObject.cs_willAccessValue(forKey:))
|
||||||
|
)
|
||||||
|
NSManagedObject.cs_swizzle(
|
||||||
|
original: #selector(NSManagedObject.willChangeValue(forKey:)),
|
||||||
|
proxy: #selector(NSManagedObject.cs_willChangeValue(forKey:))
|
||||||
|
)
|
||||||
|
NSManagedObject.cs_swizzle(
|
||||||
|
original: #selector(NSManagedObject.willChangeValue(forKey:withSetMutation:using:)),
|
||||||
|
proxy: #selector(NSManagedObject.cs_willChangeValue(forKey:withSetMutation:using:))
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(Static.isSwizzled)
|
||||||
|
}
|
||||||
|
|
||||||
|
@nonobjc
|
||||||
|
private static func cs_swizzle(original originalSelector: Selector, proxy swizzledSelector: Selector) {
|
||||||
|
|
||||||
|
let originalMethod = class_getInstanceMethod(NSManagedObject.self, originalSelector)
|
||||||
|
let swizzledMethod = class_getInstanceMethod(NSManagedObject.self, swizzledSelector)
|
||||||
|
let didAddMethod = class_addMethod(
|
||||||
|
NSManagedObject.self,
|
||||||
|
originalSelector,
|
||||||
|
method_getImplementation(swizzledMethod),
|
||||||
|
method_getTypeEncoding(swizzledMethod)
|
||||||
|
)
|
||||||
|
if didAddMethod {
|
||||||
|
|
||||||
|
class_replaceMethod(
|
||||||
|
NSManagedObject.self,
|
||||||
|
swizzledSelector,
|
||||||
|
method_getImplementation(originalMethod),
|
||||||
|
method_getTypeEncoding(originalMethod)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
method_exchangeImplementations(originalMethod, swizzledMethod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private dynamic func cs_willAccessValue(forKey key: String?) {
|
||||||
|
|
||||||
|
self.cs_willAccessValue(forKey: key)
|
||||||
|
|
||||||
|
guard CoreStore.logger.enableObjectConcurrencyDebugging else {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let context = self.managedObjectContext else {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(NSManagedObjectContext.self))."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if context.isTransactionContext {
|
||||||
|
|
||||||
|
guard let transaction = context.parentTransaction else {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) after has been deleted from its transaction."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CoreStore.assert(
|
||||||
|
transaction.isRunningInAllowedQueue(),
|
||||||
|
"Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) outside its transaction's designated queue."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if context.isDataStackContext {
|
||||||
|
|
||||||
|
guard context.parentStack != nil else {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(DataStack.self)).")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CoreStore.assert(
|
||||||
|
Thread.isMainThread,
|
||||||
|
"Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) outside the main thread."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private dynamic func cs_willChangeValue(forKey key: String?) {
|
||||||
|
|
||||||
|
self.cs_willChangeValue(forKey: key)
|
||||||
|
|
||||||
|
guard CoreStore.logger.enableObjectConcurrencyDebugging else {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let context = self.managedObjectContext else {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(NSManagedObjectContext.self))."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if context.isTransactionContext {
|
||||||
|
|
||||||
|
guard let transaction = context.parentTransaction else {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) after has been deleted from its transaction."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CoreStore.assert(
|
||||||
|
transaction.isRunningInAllowedQueue(),
|
||||||
|
"Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) outside its transaction's designated queue."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if context.isDataStackContext {
|
||||||
|
|
||||||
|
guard context.parentStack != nil else {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(DataStack.self)).")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CoreStore.assert(
|
||||||
|
Thread.isMainThread,
|
||||||
|
"Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) outside the main thread."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private dynamic func cs_willChangeValue(forKey inKey: String, withSetMutation inMutationKind: NSKeyValueSetMutationKind, using inObjects: Set<AnyHashable>) {
|
||||||
|
|
||||||
|
self.cs_willChangeValue(
|
||||||
|
forKey: inKey,
|
||||||
|
withSetMutation: inMutationKind,
|
||||||
|
using: inObjects
|
||||||
|
)
|
||||||
|
|
||||||
|
guard CoreStore.logger.enableObjectConcurrencyDebugging else {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let context = self.managedObjectContext else {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(NSManagedObjectContext.self))."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if context.isTransactionContext {
|
||||||
|
|
||||||
|
guard let transaction = context.parentTransaction else {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) after has been deleted from its transaction."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CoreStore.assert(
|
||||||
|
transaction.isRunningInAllowedQueue(),
|
||||||
|
"Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) outside its transaction's designated queue."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if context.isDataStackContext {
|
||||||
|
|
||||||
|
guard context.parentStack != nil else {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(DataStack.self)).")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CoreStore.assert(
|
||||||
|
Thread.isMainThread,
|
||||||
|
"Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) outside the main thread."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,11 @@ public enum LogLevel {
|
|||||||
*/
|
*/
|
||||||
public protocol CoreStoreLogger {
|
public protocol CoreStoreLogger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
When `true`, all `NSManagedObject` attribute and relationship access will raise an assertion when executed on the wrong transaction/datastack queue. Defaults to `false` if not implemented.
|
||||||
|
*/
|
||||||
|
var enableObjectConcurrencyDebugging: Bool { get set }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Handles log messages sent by the `CoreStore` framework.
|
Handles log messages sent by the `CoreStore` framework.
|
||||||
|
|
||||||
@@ -94,6 +99,12 @@ public protocol CoreStoreLogger {
|
|||||||
|
|
||||||
extension CoreStoreLogger {
|
extension CoreStoreLogger {
|
||||||
|
|
||||||
|
public var enableObjectConcurrencyDebugging: Bool {
|
||||||
|
|
||||||
|
get { return false }
|
||||||
|
set {}
|
||||||
|
}
|
||||||
|
|
||||||
public func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
public func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||||
|
|
||||||
Swift.fatalError(message, file: fileName, line: UInt(lineNumber))
|
Swift.fatalError(message, file: fileName, line: UInt(lineNumber))
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ import Foundation
|
|||||||
*/
|
*/
|
||||||
public final class DefaultLogger: CoreStoreLogger {
|
public final class DefaultLogger: CoreStoreLogger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
When `true`, all `NSManagedObject` attribute and relationship access will raise an assertion when executed on the wrong transaction/datastack queue. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
public var enableObjectConcurrencyDebugging: Bool = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `DefaultLogger`.
|
Creates a `DefaultLogger`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ public final class DataStack: Equatable {
|
|||||||
*/
|
*/
|
||||||
public required init(model: NSManagedObjectModel, migrationChain: MigrationChain = nil) {
|
public required init(model: NSManagedObjectModel, migrationChain: MigrationChain = nil) {
|
||||||
|
|
||||||
|
_ = DataStack.isGloballyInitialized
|
||||||
|
|
||||||
CoreStore.assert(
|
CoreStore.assert(
|
||||||
migrationChain.valid,
|
migrationChain.valid,
|
||||||
"Invalid migration chain passed to the \(cs_typeName(DataStack.self)). Check that the model versions' order is correct and that no repetitions or ambiguities exist."
|
"Invalid migration chain passed to the \(cs_typeName(DataStack.self)). Check that the model versions' order is correct and that no repetitions or ambiguities exist."
|
||||||
@@ -499,6 +501,12 @@ public final class DataStack: Equatable {
|
|||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
|
private static let isGloballyInitialized: Bool = {
|
||||||
|
|
||||||
|
NSManagedObject.cs_swizzleMethodsForLogging()
|
||||||
|
return true
|
||||||
|
}()
|
||||||
|
|
||||||
private var configurationStoreMapping = [String: NSPersistentStore]()
|
private var configurationStoreMapping = [String: NSPersistentStore]()
|
||||||
private var entityConfigurationsMapping = [String: Set<String>]()
|
private var entityConfigurationsMapping = [String: Set<String>]()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user