Add ReverseDispatchQueue.

pull/1/head
Matthew Chen 6 years ago
parent 9f04e7c5df
commit b0295b736b

@ -478,7 +478,11 @@ public class ConversationMediaView: UIView {
// views that are no longer visible, redundant loads
// of media already being loaded, don't retry media
// that can't be loaded, etc.).
private static let loadQueue = DispatchQueue(label: "org.signal.asyncMediaLoadQueue")
// * Do them in _reverse_ order. More recently enqueued
// loads more closely reflect the current view state.
// By processing in reverse order, we improve our
// "skip rate" of obsolete loads.
private static let loadQueue = ReverseDispatchQueue(label: "org.signal.asyncMediaLoadQueue")
@objc
public func loadMedia() {

@ -0,0 +1,75 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
// This is intended to be a drop-in replacement for DispatchQueue
// that processes its queue in reverse order.
@objc
public class ReverseDispatchQueue: NSObject {
private static let isVerbose: Bool = false
private let label: String
private let serialQueue: DispatchQueue
// TODO: We could allow creation with various QOS.
@objc
public required init(label: String) {
self.label = label
serialQueue = DispatchQueue(label: label)
super.init()
}
public typealias WorkBlock = () -> Void
private class Item {
let workBlock: WorkBlock
let index: UInt64
required init(workBlock : @escaping WorkBlock, index: UInt64) {
self.workBlock = workBlock
self.index = index
}
}
// These properties should only be accessed on serialQueue.
private var items = [Item]()
private var indexCounter: UInt64 = 0
@objc
public func async(workBlock : @escaping WorkBlock) {
serialQueue.async {
self.indexCounter = self.indexCounter + 1
let index = self.indexCounter
let item = Item(workBlock: workBlock, index: index )
self.items.append(item)
if ReverseDispatchQueue.isVerbose {
Logger.verbose("Enqueued[\(self.label)]: \(item.index)")
}
self.process()
}
}
private func process() {
serialQueue.async {
// Note that we popLast() so that we process
// the queue in the _reverse_ order from
// which it was enqueued.
guard let item = self.items.popLast() else {
// No enqueued work to do.
return
}
if ReverseDispatchQueue.isVerbose {
Logger.verbose("Processing[\(self.label)]: \(item.index)")
}
item.workBlock()
self.process()
}
}
}
Loading…
Cancel
Save