diff --git a/CoreStore.podspec b/CoreStore.podspec index e3fa324..b4539d4 100644 --- a/CoreStore.podspec +++ b/CoreStore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "CoreStore" - s.version = "3.0.2" + s.version = "3.0.3" s.license = "MIT" s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift" s.homepage = "https://github.com/JohnEstropia/CoreStore" diff --git a/CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj b/CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj index 1a19818..7e80f73 100644 --- a/CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj +++ b/CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj @@ -378,8 +378,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -423,8 +425,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; diff --git a/Sources/Info.plist b/Sources/Info.plist index 49ca846..0ea7266 100644 --- a/Sources/Info.plist +++ b/Sources/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 3.0.2 + 3.0.3 CFBundleSignature ???? CFBundleVersion diff --git a/Sources/Internal/NSManagedObject+Logging.swift b/Sources/Internal/NSManagedObject+Logging.swift index a6e83a6..fe4a0fa 100644 --- a/Sources/Internal/NSManagedObject+Logging.swift +++ b/Sources/Internal/NSManagedObject+Logging.swift @@ -31,210 +31,211 @@ import CoreData 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) { - - 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 - } - } + // TODO: test before release (rolled back) +// @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) { +// +// 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 +// } +// } } diff --git a/Sources/Logging/CoreStoreLogger.swift b/Sources/Logging/CoreStoreLogger.swift index 9e9e46c..1f6832f 100644 --- a/Sources/Logging/CoreStoreLogger.swift +++ b/Sources/Logging/CoreStoreLogger.swift @@ -50,7 +50,8 @@ 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 } + // TODO: test before release (rolled back) +// var enableObjectConcurrencyDebugging: Bool { get set } /** Handles log messages sent by the `CoreStore` framework. @@ -99,11 +100,12 @@ public protocol CoreStoreLogger { extension CoreStoreLogger { - public var enableObjectConcurrencyDebugging: Bool { - - get { return false } - set {} - } + // TODO: test before release (rolled back) +// public var enableObjectConcurrencyDebugging: Bool { +// +// get { return false } +// set {} +// } public func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) { diff --git a/Sources/Logging/DefaultLogger.swift b/Sources/Logging/DefaultLogger.swift index 1f558ab..380fdf5 100644 --- a/Sources/Logging/DefaultLogger.swift +++ b/Sources/Logging/DefaultLogger.swift @@ -36,7 +36,8 @@ 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 + // TODO: test before release (rolled back) +// public var enableObjectConcurrencyDebugging: Bool = false /** Creates a `DefaultLogger`. diff --git a/Sources/Setup/DataStack.swift b/Sources/Setup/DataStack.swift index e4fc2f9..80d4ac7 100644 --- a/Sources/Setup/DataStack.swift +++ b/Sources/Setup/DataStack.swift @@ -58,8 +58,9 @@ public final class DataStack: Equatable { - parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. */ public required init(model: NSManagedObjectModel, migrationChain: MigrationChain = nil) { - - _ = DataStack.isGloballyInitialized + + // TODO: test before release (rolled back) +// _ = DataStack.isGloballyInitialized CoreStore.assert( migrationChain.valid, @@ -501,11 +502,12 @@ public final class DataStack: Equatable { // MARK: Private - private static let isGloballyInitialized: Bool = { - - NSManagedObject.cs_swizzleMethodsForLogging() - return true - }() + // TODO: test before release (rolled back) +// private static let isGloballyInitialized: Bool = { +// +// NSManagedObject.cs_swizzleMethodsForLogging() +// return true +// }() private var configurationStoreMapping = [String: NSPersistentStore]() private var entityConfigurationsMapping = [String: Set]()