From 48a86947205787310f78245ceebf126506c5ebe8 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Wed, 30 Mar 2016 05:22:05 +0900 Subject: [PATCH 1/4] attempt to fix closure deallocation bug (#58) --- .../Internal/CoreStoreFetchedResultsController.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CoreStore/Internal/CoreStoreFetchedResultsController.swift b/CoreStore/Internal/CoreStoreFetchedResultsController.swift index 8c35457..4312c2e 100644 --- a/CoreStore/Internal/CoreStoreFetchedResultsController.swift +++ b/CoreStore/Internal/CoreStoreFetchedResultsController.swift @@ -56,7 +56,7 @@ internal final class CoreStoreFetchedResultsController: NSFe if let from = from { - self.reapplyAffectedStores = { + self.reapplyAffectedStores = { fetchRequest, context in return from.applyAffectedStoresForFetchedRequest(fetchRequest, context: context) } @@ -68,7 +68,7 @@ internal final class CoreStoreFetchedResultsController: NSFe fatalError("Attempted to create an \(typeName(NSFetchedResultsController)) without a From clause or an NSEntityDescription.") } - self.reapplyAffectedStores = { + self.reapplyAffectedStores = { fetchRequest, context in return from.applyAffectedStoresForFetchedRequest(fetchRequest, context: context) } @@ -84,7 +84,7 @@ internal final class CoreStoreFetchedResultsController: NSFe internal func performFetchFromSpecifiedStores() throws { - if !self.reapplyAffectedStores() { + if !self.reapplyAffectedStores(fetchRequest: self.fetchRequest, context: self.managedObjectContext) { CoreStore.log( .Warning, @@ -97,5 +97,5 @@ internal final class CoreStoreFetchedResultsController: NSFe // MARK: Private - private let reapplyAffectedStores: () -> Bool + private let reapplyAffectedStores: (fetchRequest: NSFetchRequest, context: NSManagedObjectContext) -> Bool } From 06e952af8aa32b6b385b9b8f77c59c59cecbf83c Mon Sep 17 00:00:00 2001 From: John Rommel Estropia Date: Wed, 30 Mar 2016 20:28:10 +0900 Subject: [PATCH 2/4] clear FRC delegate on deinit --- CoreStore/Internal/CoreStoreFetchedResultsController.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CoreStore/Internal/CoreStoreFetchedResultsController.swift b/CoreStore/Internal/CoreStoreFetchedResultsController.swift index 4312c2e..1286713 100644 --- a/CoreStore/Internal/CoreStoreFetchedResultsController.swift +++ b/CoreStore/Internal/CoreStoreFetchedResultsController.swift @@ -94,6 +94,11 @@ internal final class CoreStoreFetchedResultsController: NSFe try self.performFetch() } + deinit { + + self.delegate = nil + } + // MARK: Private From 410feda5cdd67b521cd862483f7542f36ca121e7 Mon Sep 17 00:00:00 2001 From: John Rommel Estropia Date: Wed, 30 Mar 2016 20:47:13 +0900 Subject: [PATCH 3/4] tidy up --- CoreStore.xcodeproj/project.pbxproj | 4 ---- CoreStore/Internal/NSManagedObjectContext+Transaction.swift | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index a4841cd..125ae7a 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -283,7 +283,6 @@ B5D9E32F1CA2C317007A9D52 /* CoreStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F03A53519C5C6DA005002A5 /* CoreStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; B5D9E3431CA2C6C4007A9D52 /* GCDBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D9E3371CA2C6BF007A9D52 /* GCDBlock.swift */; }; B5D9E3441CA2C6C4007A9D52 /* GCDGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D9E3381CA2C6BF007A9D52 /* GCDGroup.swift */; }; - B5D9E3451CA2C6C4007A9D52 /* GCDKit.h in Headers */ = {isa = PBXBuildFile; fileRef = B5D9E3391CA2C6BF007A9D52 /* GCDKit.h */; }; B5D9E3461CA2C6C4007A9D52 /* GCDQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D9E33A1CA2C6BF007A9D52 /* GCDQueue.swift */; }; B5D9E3471CA2C6C4007A9D52 /* GCDSemaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D9E33B1CA2C6BF007A9D52 /* GCDSemaphore.swift */; }; B5D9E3481CA2C6C4007A9D52 /* GCDTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D9E33C1CA2C6BF007A9D52 /* GCDTimer.swift */; }; @@ -407,7 +406,6 @@ B5D9E3341CA2C317007A9D52 /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B5D9E3371CA2C6BF007A9D52 /* GCDBlock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GCDBlock.swift; path = Carthage/Checkouts/GCDKit/Sources/GCDBlock.swift; sourceTree = ""; }; B5D9E3381CA2C6BF007A9D52 /* GCDGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GCDGroup.swift; path = Carthage/Checkouts/GCDKit/Sources/GCDGroup.swift; sourceTree = ""; }; - B5D9E3391CA2C6BF007A9D52 /* GCDKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GCDKit.h; path = Carthage/Checkouts/GCDKit/Sources/GCDKit.h; sourceTree = ""; }; B5D9E33A1CA2C6BF007A9D52 /* GCDQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GCDQueue.swift; path = Carthage/Checkouts/GCDKit/Sources/GCDQueue.swift; sourceTree = ""; }; B5D9E33B1CA2C6BF007A9D52 /* GCDSemaphore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GCDSemaphore.swift; path = Carthage/Checkouts/GCDKit/Sources/GCDSemaphore.swift; sourceTree = ""; }; B5D9E33C1CA2C6BF007A9D52 /* GCDTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GCDTimer.swift; path = Carthage/Checkouts/GCDKit/Sources/GCDTimer.swift; sourceTree = ""; }; @@ -647,7 +645,6 @@ children = ( B5D9E3371CA2C6BF007A9D52 /* GCDBlock.swift */, B5D9E3381CA2C6BF007A9D52 /* GCDGroup.swift */, - B5D9E3391CA2C6BF007A9D52 /* GCDKit.h */, B5D9E33A1CA2C6BF007A9D52 /* GCDQueue.swift */, B5D9E33B1CA2C6BF007A9D52 /* GCDSemaphore.swift */, B5D9E33C1CA2C6BF007A9D52 /* GCDTimer.swift */, @@ -819,7 +816,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - B5D9E3451CA2C6C4007A9D52 /* GCDKit.h in Headers */, B5D9E32F1CA2C317007A9D52 /* CoreStore.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/CoreStore/Internal/NSManagedObjectContext+Transaction.swift b/CoreStore/Internal/NSManagedObjectContext+Transaction.swift index 255db60..e64332c 100644 --- a/CoreStore/Internal/NSManagedObjectContext+Transaction.swift +++ b/CoreStore/Internal/NSManagedObjectContext+Transaction.swift @@ -80,7 +80,7 @@ internal extension NSManagedObjectContext { var result = SaveResult(hasChanges: false) - self.performBlockAndWait { [unowned self] () -> Void in + self.performBlockAndWait { guard self.hasChanges else { @@ -124,7 +124,7 @@ internal extension NSManagedObjectContext { internal func saveAsynchronouslyWithCompletion(completion: ((result: SaveResult) -> Void) = { _ in }) { - self.performBlock { () -> Void in + self.performBlock { guard self.hasChanges else { From 633ab0a2498ebc655f6f75d5d93e35c4251f05f0 Mon Sep 17 00:00:00 2001 From: John Rommel Estropia Date: Wed, 30 Mar 2016 21:16:10 +0900 Subject: [PATCH 4/4] cache fetchClauses in property so closures do not retain them indeterminately --- CoreStore/Observing/ListMonitor.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CoreStore/Observing/ListMonitor.swift b/CoreStore/Observing/ListMonitor.swift index fd0f540..d0c5bf5 100644 --- a/CoreStore/Observing/ListMonitor.swift +++ b/CoreStore/Observing/ListMonitor.swift @@ -891,6 +891,7 @@ public final class ListMonitor { object: self ) } + self.fetchClauses = fetchClauses self.taskGroup.notify(.Main) { [weak self] () -> Void in @@ -902,7 +903,7 @@ public final class ListMonitor { strongSelf.fetchedResultsControllerDelegate.enabled = false let fetchRequest = strongSelf.fetchedResultsController.fetchRequest - for clause in fetchClauses { + for clause in strongSelf.fetchClauses { clause.applyToFetchRequest(fetchRequest) } @@ -1019,6 +1020,7 @@ public final class ListMonitor { self.sectionIndexTransformer = { $0 } } self.transactionQueue = transactionQueue + self.fetchClauses = fetchClauses fetchedResultsControllerDelegate.handler = self fetchedResultsControllerDelegate.fetchedResultsController = fetchedResultsController @@ -1045,7 +1047,7 @@ public final class ListMonitor { return } - self.refetch(fetchClauses) + self.refetch(self.fetchClauses) } ) @@ -1068,7 +1070,7 @@ public final class ListMonitor { if previousStores != currentStores { - self.refetch(fetchClauses) + self.refetch(self.fetchClauses) } } @@ -1130,6 +1132,7 @@ public final class ListMonitor { private var observerForDidChangePersistentStore: NotificationObserver! private let taskGroup = GCDGroup() private let transactionQueue: GCDQueue + private var fetchClauses: [FetchClause] private var willChangeListKey: Void? private var didChangeListKey: Void?