Make fetching all unread counts an operation. Cancel it when the account is suspending. Turning things like this into operations goes to fixing the dreaded 0xdead10cc crashes.
This commit is contained in:
parent
04f4e8655b
commit
dc9243dcc7
|
@ -231,6 +231,11 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||
return delegate.refreshProgress
|
||||
}
|
||||
|
||||
private var operationQueue = MainThreadOperationQueue()
|
||||
private enum OperationName {
|
||||
static let FetchAllUnreadCounts = "FetchAllUnreadCounts"
|
||||
}
|
||||
|
||||
init?(dataFolder: String, type: AccountType, accountID: String, transport: Transport? = nil) {
|
||||
switch type {
|
||||
case .onMyMac:
|
||||
|
@ -414,6 +419,8 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||
}
|
||||
|
||||
public func suspendDatabase() {
|
||||
operationQueue.suspend()
|
||||
cancelDiscardableOperations()
|
||||
database.suspend()
|
||||
save()
|
||||
metadataFile.suspend()
|
||||
|
@ -426,6 +433,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||
public func resumeDatabaseAndDelegate() {
|
||||
database.resume()
|
||||
delegate.resume()
|
||||
operationQueue.resume()
|
||||
}
|
||||
|
||||
/// Reload OPML, etc.
|
||||
|
@ -448,6 +456,10 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||
delegate.accountWillBeDeleted(self)
|
||||
}
|
||||
|
||||
public func cancelDiscardableOperations() {
|
||||
operationQueue.cancelOperations(named: OperationName.FetchAllUnreadCounts)
|
||||
}
|
||||
|
||||
func loadOPMLItems(_ items: [RSOPMLItem], parentFolder: Folder?) {
|
||||
var feedsToAdd = Set<WebFeed>()
|
||||
|
||||
|
@ -1226,24 +1238,31 @@ private extension Account {
|
|||
|
||||
func fetchAllUnreadCounts() {
|
||||
fetchingAllUnreadCounts = true
|
||||
operationQueue.cancelOperations(named: OperationName.FetchAllUnreadCounts)
|
||||
|
||||
database.fetchAllNonZeroUnreadCounts { (unreadCountDictionaryResult) in
|
||||
if let unreadCountDictionary = try? unreadCountDictionaryResult.get() {
|
||||
self.flattenedWebFeeds().forEach{ (feed) in
|
||||
// When the unread count is zero, it won’t appear in unreadCountDictionary.
|
||||
if let unreadCount = unreadCountDictionary[feed.webFeedID] {
|
||||
feed.unreadCount = unreadCount
|
||||
}
|
||||
else {
|
||||
feed.unreadCount = 0
|
||||
}
|
||||
let operation = database.createFetchAllUnreadCountsOperation()
|
||||
operation.name = OperationName.FetchAllUnreadCounts
|
||||
operation.completionBlock = { operation in
|
||||
let fetchOperation = operation as! FetchAllUnreadCountsOperation
|
||||
guard let unreadCountDictionary = fetchOperation.unreadCountDictionary else {
|
||||
return
|
||||
}
|
||||
self.processUnreadCounts(unreadCountDictionary: unreadCountDictionary)
|
||||
|
||||
self.fetchingAllUnreadCounts = false
|
||||
self.updateUnreadCount()
|
||||
self.isUnreadCountsInitialized = true
|
||||
self.postUnreadCountDidInitializeNotification()
|
||||
}
|
||||
|
||||
operationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
func processUnreadCounts(unreadCountDictionary: UnreadCountDictionary) {
|
||||
for feed in flattenedWebFeeds() {
|
||||
// When the unread count is zero, it won’t appear in unreadCountDictionary.
|
||||
let unreadCount = unreadCountDictionary[feed.webFeedID] ?? 0
|
||||
feed.unreadCount = unreadCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,10 +141,6 @@ public final class ArticlesDatabase {
|
|||
articlesTable.fetchUnreadCounts(webFeedIDs, completion)
|
||||
}
|
||||
|
||||
public func fetchAllNonZeroUnreadCounts(_ completion: @escaping UnreadCountDictionaryCompletionBlock) {
|
||||
articlesTable.fetchAllUnreadCounts(completion)
|
||||
}
|
||||
|
||||
public func fetchUnreadCountForToday(for webFeedIDs: Set<String>, completion: @escaping SingleUnreadCountCompletionBlock) {
|
||||
fetchUnreadCount(for: webFeedIDs, since: todayCutoffDate(), completion: completion)
|
||||
}
|
||||
|
@ -195,6 +191,13 @@ public final class ArticlesDatabase {
|
|||
articlesTable.createStatusesIfNeeded(articleIDs, completion)
|
||||
}
|
||||
|
||||
// MARK: - Operations
|
||||
|
||||
/// Create and return an operation that fetches all non-zero unread counts.
|
||||
public func createFetchAllUnreadCountsOperation() -> FetchAllUnreadCountsOperation {
|
||||
return articlesTable.createFetchAllUnreadCountsOperation()
|
||||
}
|
||||
|
||||
// MARK: - Suspend and Resume (for iOS)
|
||||
|
||||
/// Close the database and stop running database calls.
|
||||
|
|
|
@ -521,6 +521,10 @@ final class ArticlesTable: DatabaseTable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createFetchAllUnreadCountsOperation() -> FetchAllUnreadCountsOperation {
|
||||
return FetchAllUnreadCountsOperation(databaseQueue: queue, cutoffDate: articleCutoffDate)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
|
|
@ -10,16 +10,16 @@ import Foundation
|
|||
import RSCore
|
||||
import RSDatabase
|
||||
|
||||
final class FetchAllUnreadCountsOperation: MainThreadOperation {
|
||||
public final class FetchAllUnreadCountsOperation: MainThreadOperation {
|
||||
|
||||
public var unreadCountDictionary: UnreadCountDictionary?
|
||||
|
||||
// MainThreadOperation
|
||||
var isCanceled = false
|
||||
var id: Int?
|
||||
weak var operationDelegate: MainThreadOperationDelegate?
|
||||
var name: String? = "FetchAllUnreadCountsOperation"
|
||||
var completionBlock: MainThreadOperation.MainThreadOperationCompletionBlock?
|
||||
public var isCanceled = false
|
||||
public var id: Int?
|
||||
public weak var operationDelegate: MainThreadOperationDelegate?
|
||||
public var name: String?
|
||||
public var completionBlock: MainThreadOperation.MainThreadOperationCompletionBlock?
|
||||
|
||||
private let queue: DatabaseQueue
|
||||
private let cutoffDate: Date
|
||||
|
@ -29,7 +29,7 @@ final class FetchAllUnreadCountsOperation: MainThreadOperation {
|
|||
self.cutoffDate = cutoffDate
|
||||
}
|
||||
|
||||
func run() {
|
||||
public func run() {
|
||||
queue.runInDatabase { databaseResult in
|
||||
if self.isCanceled {
|
||||
self.informOperationDelegateOfCompletion()
|
||||
|
@ -48,14 +48,6 @@ final class FetchAllUnreadCountsOperation: MainThreadOperation {
|
|||
|
||||
private extension FetchAllUnreadCountsOperation {
|
||||
|
||||
func informOperationDelegateOfCompletion() {
|
||||
DispatchQueue.main.async {
|
||||
if !self.isCanceled {
|
||||
self.operationDelegate?.operationDidComplete(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fetchUnreadCounts(_ database: FMDatabase) {
|
||||
let sql = "select distinct feedID, count(*) from articles natural join statuses where read=0 and userDeleted=0 and (starred=1 or dateArrived>?) group by feedID;"
|
||||
|
||||
|
|
Loading…
Reference in New Issue