From 31a2afb067590315126a8dc377ecf799ca9aa653 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Sun, 13 Oct 2019 22:08:05 -0700 Subject: [PATCH] Fix crashing bug in FetchRequestQueue by making sure the completion is called not more than once from FetchRequestOperation. Fix #1133. --- .../Timeline/FetchRequestOperation.swift | 28 ++++++++++++------- .../Timeline/FetchRequestQueue.swift | 5 ++-- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/Mac/MainWindow/Timeline/FetchRequestOperation.swift b/Mac/MainWindow/Timeline/FetchRequestOperation.swift index 223b2095b..ff9e0664b 100644 --- a/Mac/MainWindow/Timeline/FetchRequestOperation.swift +++ b/Mac/MainWindow/Timeline/FetchRequestOperation.swift @@ -16,7 +16,7 @@ import Articles typealias FetchRequestOperationResultBlock = (Set
, FetchRequestOperation) -> Void -class FetchRequestOperation { +final class FetchRequestOperation { let id: Int let resultBlock: FetchRequestOperationResultBlock @@ -35,8 +35,17 @@ class FetchRequestOperation { precondition(Thread.isMainThread) precondition(!isFinished) + var didCallCompletion = false + + func callCompletionIfNeeded() { + if !didCallCompletion { + didCallCompletion = true + completion(self) + } + } + if isCanceled { - completion(self) + callCompletionIfNeeded() return } @@ -44,7 +53,7 @@ class FetchRequestOperation { if articleFetchers.isEmpty { isFinished = true resultBlock(Set
(), self) - completion(self) + callCompletionIfNeeded() return } @@ -52,22 +61,21 @@ class FetchRequestOperation { var fetchersReturned = 0 var fetchedArticles = Set
() for articleFetcher in articleFetchers { - var didCallCompletion = false articleFetcher.fetchArticlesAsync { (articles) in precondition(Thread.isMainThread) - if self.isCanceled { - if !didCallCompletion { - didCallCompletion = true - completion(self) - } + guard !self.isCanceled else { + callCompletionIfNeeded() return } + + assert(!self.isFinished) + fetchedArticles.formUnion(articles) fetchersReturned += 1 if fetchersReturned == numberOfFetchers { self.isFinished = true self.resultBlock(fetchedArticles, self) - completion(self) + callCompletionIfNeeded() } } } diff --git a/Mac/MainWindow/Timeline/FetchRequestQueue.swift b/Mac/MainWindow/Timeline/FetchRequestQueue.swift index d68e21c98..6ecb72a9f 100644 --- a/Mac/MainWindow/Timeline/FetchRequestQueue.swift +++ b/Mac/MainWindow/Timeline/FetchRequestQueue.swift @@ -10,7 +10,7 @@ import Foundation // Main thread only. -class FetchRequestQueue { +final class FetchRequestQueue { private var pendingRequests = [FetchRequestOperation]() private var currentRequest: FetchRequestOperation? = nil @@ -40,9 +40,8 @@ private extension FetchRequestQueue { currentRequest = requestToRun pendingRequests.removeFirst() - requestToRun.run { (fetchRequestOperation) in + currentRequest.run { (fetchRequestOperation) in precondition(fetchRequestOperation === self.currentRequest) - precondition(fetchRequestOperation === requestToRun) self.currentRequest = nil self.runNextRequestIfNeeded() }