From 3d82ee18c7457b41d0f1f389b5e46eeb95623408 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Sat, 3 Oct 2020 14:36:57 +0900 Subject: [PATCH 1/5] reinclude LegacyDemo in workspace --- CoreStore.xcworkspace/contents.xcworkspacedata | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CoreStore.xcworkspace/contents.xcworkspacedata b/CoreStore.xcworkspace/contents.xcworkspacedata index a57c826..23b89e6 100644 --- a/CoreStore.xcworkspace/contents.xcworkspacedata +++ b/CoreStore.xcworkspace/contents.xcworkspacedata @@ -8,6 +8,6 @@ location = "group:CoreStore.xcodeproj"> + location = "group:LegacyDemo/LegacyDemo.xcodeproj"> From 4ec2b2e3117b0b51a1e29090c0c304fbd04e0c3c Mon Sep 17 00:00:00 2001 From: John Estropia Date: Mon, 5 Oct 2020 23:12:17 +0900 Subject: [PATCH 2/5] Optimize ListSnapshot collection implementation --- ...Internals.DiffableDataSourceSnapshot.swift | 63 +++++++++++++++- Sources/ListSnapshot.swift | 74 ++++++++++++++++--- 2 files changed, 125 insertions(+), 12 deletions(-) diff --git a/Sources/Internals.DiffableDataSourceSnapshot.swift b/Sources/Internals.DiffableDataSourceSnapshot.swift index e4388c6..c46bc38 100644 --- a/Sources/Internals.DiffableDataSourceSnapshot.swift +++ b/Sources/Internals.DiffableDataSourceSnapshot.swift @@ -78,7 +78,7 @@ extension Internals { var numberOfItems: Int { - return self.structure.allItemIDs.count + return self.structure.allItemsCount } var numberOfSections: Int { @@ -106,6 +106,59 @@ extension Internals { return self.itemIdentifiers(inSection: identifier).count } + func itemIdentifier(atAllItemsIndex index: Int) -> NSManagedObjectID? { + + guard index >= 0 else { + + return nil + } + var remainingIndex = index + for section in self.structure.sections { + + let elements = section.elements + let sectionCount = elements.count + if remainingIndex < sectionCount { + + return elements[remainingIndex].differenceIdentifier + } + + remainingIndex -= sectionCount + } + return nil + } + + func itemIdentifiers(atAllItemsBounds bounds: Range) -> [NSManagedObjectID] { + + var remainingIndex = bounds.lowerBound + var itemIdentifiers: [NSManagedObjectID] = [] + for section in self.structure.sections { + + let elements = section.elements + let sectionCount = elements.count + if remainingIndex < sectionCount { + + itemIdentifiers.append( + contentsOf: elements[remainingIndex..= bounds.count { + + return itemIdentifiers + } + + remainingIndex -= sectionCount + } + return itemIdentifiers + } + func itemIdentifiers(inSection identifier: String) -> [NSManagedObjectID] { return self.structure.items(in: identifier) @@ -332,6 +385,14 @@ extension Internals { return self.sections.map({ $0.differenceIdentifier }) } + var allItemsCount: Int { + + return self.sections.reduce(into: 0) { (result, section) in + + result += section.elements.count + } + } + var allItemIDs: [NSManagedObjectID] { return self.sections.lazy.flatMap({ $0.elements }).map({ $0.differenceIdentifier }) diff --git a/Sources/ListSnapshot.swift b/Sources/ListSnapshot.swift index 9ed1f92..d1bea9f 100644 --- a/Sources/ListSnapshot.swift +++ b/Sources/ListSnapshot.swift @@ -71,7 +71,7 @@ public struct ListSnapshot: RandomAccessCollection, Hashable { public subscript(index: Index) -> ObjectPublisher { let context = self.context! - let itemID = self.diffableSnapshot.itemIdentifiers[index] + let itemID = self.diffableSnapshot.itemIdentifier(atAllItemsIndex: index)! return context.objectPublisher(objectID: itemID) } @@ -83,16 +83,13 @@ public struct ListSnapshot: RandomAccessCollection, Hashable { */ public subscript(safeIndex index: Index) -> ObjectPublisher? { - guard let context = self.context else { + guard + let context = self.context, + let itemID = self.diffableSnapshot.itemIdentifier(atAllItemsIndex: index) + else { return nil } - let itemIDs = self.diffableSnapshot.itemIdentifiers - guard itemIDs.indices.contains(index) else { - - return nil - } - let itemID = itemIDs[index] return context.objectPublisher(objectID: itemID) } @@ -603,14 +600,69 @@ public struct ListSnapshot: RandomAccessCollection, Hashable { public var startIndex: Index { - return self.diffableSnapshot.itemIdentifiers.startIndex + return 0 } public var endIndex: Index { - return self.diffableSnapshot.itemIdentifiers.endIndex + return self.diffableSnapshot.numberOfItems } - + + public func index(after i: Index) -> Index { + + return i + 1 + } + + public func formIndex(after i: inout Index) { + + return i += 1 + } + + public func index(before i: Index) -> Index { + + return i - 1 + } + + public func formIndex(before i: inout Index) { + + return i -= 1 + } + + + // MARK: BidirectionalCollection + + public func index(_ i: Index, offsetBy distance: Int) -> Index { + + return i + distance + } + + public func index(_ i: Index, offsetBy distance: Int, limitedBy limit: Int) -> Index? { + + let length = limit - i + if distance > 0 + ? length >= 0 && length < distance + : length <= 0 && length > distance { + + return nil + } + return i + distance + } + + public func distance(from start: Index, to end: Index) -> Int { + + return end - start + } + + public subscript(bounds: Range) -> ArraySlice { + + guard let context = self.context else { + + return .init() + } + let itemIDs = self.diffableSnapshot.itemIdentifiers(atAllItemsBounds: bounds) + return ArraySlice(itemIDs.map(context.objectPublisher(objectID:))) + } + // MARK: Sequence From f136549b463e3a2840626953fb620e275d27cbbd Mon Sep 17 00:00:00 2001 From: John Estropia Date: Fri, 9 Oct 2020 20:14:04 +0900 Subject: [PATCH 3/5] prevent creation of ObjectSnapshot if object is already deleted --- Sources/DynamicObject.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/DynamicObject.swift b/Sources/DynamicObject.swift index 48dd3e7..42a446a 100644 --- a/Sources/DynamicObject.swift +++ b/Sources/DynamicObject.swift @@ -217,7 +217,8 @@ extension CoreStoreObject { guard let object = context.fetchExisting(id) as CoreStoreObject?, - let rawObject = object.rawObject + let rawObject = object.rawObject, + !rawObject.isDeleted else { return nil From 74721b5c127a9158804b225f7ecdc683a93325fe Mon Sep 17 00:00:00 2001 From: John Estropia Date: Sat, 10 Oct 2020 16:55:35 +0900 Subject: [PATCH 4/5] allow ObjectSnapshot and ObjectPublisher as parameter to Where clauses --- Sources/KeyPath+Querying.swift | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Sources/KeyPath+Querying.swift b/Sources/KeyPath+Querying.swift index 1fd8ed2..ceaf7ae 100644 --- a/Sources/KeyPath+Querying.swift +++ b/Sources/KeyPath+Querying.swift @@ -267,6 +267,17 @@ public func == (_ keyPath: KeyPath return Where(keyPath._kvcKeyPathString!, isEqualTo: objectID) } +/** + Creates a `Where` clause by comparing if a property is equal to a value + ``` + let dog = dataStack.fetchOne(From().where(\.master == john)) + ``` + */ +public func == (_ keyPath: KeyPath, _ object: O) -> Where where O.ObjectType: NSManagedObject { + + return Where(keyPath._kvcKeyPathString!, isEqualTo: object.cs_id()) +} + /** Creates a `Where` clause by comparing if a property is not equal to a value ``` @@ -278,6 +289,17 @@ public func != (_ keyPath: KeyPath return !Where(keyPath._kvcKeyPathString!, isEqualTo: objectID) } +/** + Creates a `Where` clause by comparing if a property is not equal to a value + ``` + let dog = dataStack.fetchOne(From().where(\.master != john)) + ``` + */ +public func != (_ keyPath: KeyPath, _ object: O) -> Where where O.ObjectType: NSManagedObject { + + return !Where(keyPath._kvcKeyPathString!, isEqualTo: object.cs_id()) +} + /** Creates a `Where` clause by checking if a sequence contains a value of a property ``` @@ -303,6 +325,17 @@ public func == (_ keyPath: KeyPath(keyPath._kvcKeyPathString!, isEqualTo: object) } +/** + Creates a `Where` clause by comparing if a property is equal to a value + ``` + let dog = dataStack.fetchOne(From().where(\.master == john)) + ``` + */ +public func == (_ keyPath: KeyPath>, _ object: O?) -> Where where O.ObjectType: NSManagedObject { + + return Where(keyPath._kvcKeyPathString!, isEqualTo: object?.cs_toRaw()) +} + /** Creates a `Where` clause by comparing if a property is not equal to a value ``` @@ -314,6 +347,17 @@ public func != (_ keyPath: KeyPath(keyPath._kvcKeyPathString!, isEqualTo: object) } +/** + Creates a `Where` clause by comparing if a property is not equal to a value + ``` + let dog = dataStack.fetchOne(From().where(\.master != john)) + ``` + */ +public func != (_ keyPath: KeyPath>, _ object: O?) -> Where where O.ObjectType: NSManagedObject { + + return !Where(keyPath._kvcKeyPathString!, isEqualTo: object?.cs_toRaw()) +} + /** Creates a `Where` clause by checking if a sequence contains a value of a property ``` @@ -690,6 +734,17 @@ public func == (_ keyPath: KeyPath(O.meta[keyPath: keyPath].keyPath, isEqualTo: object) } +/** + Creates a `Where` clause by comparing if a property is equal to a value + ``` + let dog = dataStack.fetchOne(From().where(\.master == john)) + ``` + */ +public func == (_ keyPath: KeyPath.Relationship>, _ object: R?) -> Where where D.DestinationObjectType == R.ObjectType { + + return Where(O.meta[keyPath: keyPath].keyPath, isEqualTo: object?.objectID()) +} + /** Creates a `Where` clause by comparing if a property is equal to a value ``` @@ -723,6 +778,17 @@ public func != (_ keyPath: KeyPath(O.meta[keyPath: keyPath].keyPath, isEqualTo: object) } +/** + Creates a `Where` clause by comparing if a property is not equal to a value + ``` + let dog = dataStack.fetchOne(From().where(\.master != john)) + ``` + */ +public func != (_ keyPath: KeyPath.Relationship>, _ object: R?) -> Where where D.DestinationObjectType == R.ObjectType { + + return !Where(O.meta[keyPath: keyPath].keyPath, isEqualTo: object?.objectID()) +} + /** Creates a `Where` clause by comparing if a property is not equal to a value ``` From a40df37192622b093321fc2003f4a5cbe3860ffb Mon Sep 17 00:00:00 2001 From: John Estropia Date: Wed, 11 Nov 2020 13:29:02 +0900 Subject: [PATCH 5/5] version bump --- CoreStore.podspec | 2 +- CoreStore.xcodeproj/project.pbxproj | 16 ++++++++-------- README.md | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CoreStore.podspec b/CoreStore.podspec index e9bdd8d..646ea17 100644 --- a/CoreStore.podspec +++ b/CoreStore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "CoreStore" - s.version = "7.3.0" + s.version = "7.3.1" s.swift_version = "5.3" s.license = "MIT" s.homepage = "https://github.com/JohnEstropia/CoreStore" diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index f074279..8c1e779 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -3413,7 +3413,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 7.3.0; + MARKETING_VERSION = 7.3.1; OTHER_LDFLAGS = ( "-weak_framework", Combine, @@ -3436,7 +3436,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 7.3.0; + MARKETING_VERSION = 7.3.1; OTHER_LDFLAGS = ( "-weak_framework", Combine, @@ -3496,7 +3496,7 @@ GCC_NO_COMMON_BLOCKS = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 7.3.0; + MARKETING_VERSION = 7.3.1; OTHER_LDFLAGS = ( "-weak_framework", Combine, @@ -3522,7 +3522,7 @@ GCC_NO_COMMON_BLOCKS = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 7.3.0; + MARKETING_VERSION = 7.3.1; OTHER_LDFLAGS = ( "-weak_framework", Combine, @@ -3587,7 +3587,7 @@ GCC_NO_COMMON_BLOCKS = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 7.3.0; + MARKETING_VERSION = 7.3.1; OTHER_LDFLAGS = ( "-weak_framework", Combine, @@ -3616,7 +3616,7 @@ GCC_NO_COMMON_BLOCKS = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 7.3.0; + MARKETING_VERSION = 7.3.1; OTHER_LDFLAGS = ( "-weak_framework", Combine, @@ -3682,7 +3682,7 @@ GCC_NO_COMMON_BLOCKS = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 7.3.0; + MARKETING_VERSION = 7.3.1; OTHER_LDFLAGS = ( "-weak_framework", Combine, @@ -3710,7 +3710,7 @@ GCC_NO_COMMON_BLOCKS = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 7.3.0; + MARKETING_VERSION = 7.3.1; OTHER_LDFLAGS = ( "-weak_framework", Combine, diff --git a/README.md b/README.md index ec5ade7..750be08 100644 --- a/README.md +++ b/README.md @@ -2095,7 +2095,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift #### Install with Swift Package Manager: ```swift dependencies: [ - .package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "7.3.0")) + .package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "7.3.1")) ] ``` Declare `import CoreStore` in your swift file to use the library.