Fix profile header image not showing up on first load

The issue occurred because the profile header would kick off a request
upon loading, then the profile table would request the initial set of
statuses shortly thereafter which would result in reloadData being called
which would cancel the request without removing the group, so the request
generated by the newly-reloaded header cell would attach a callback to
the cancelled request, resulting in the header image never displaying.
This commit is contained in:
Shadowfacts 2020-06-15 22:34:42 -04:00
parent 36326e4469
commit d27bddb2ca
2 changed files with 32 additions and 26 deletions

View File

@ -18,7 +18,7 @@ class ImageCache {
let cache: Cache<Data>
var requests = [URL: RequestGroup]()
private var groups = [URL: RequestGroup]()
init(name: String, memoryExpiry expiry: Expiry) {
let storage = MemoryStorage<Data>(config: MemoryConfig(expiry: expiry))
@ -43,14 +43,18 @@ class ImageCache {
completion?(data)
return nil
} else {
if let completion = completion, let group = requests[url] {
if let completion = completion, let group = groups[url] {
return group.addCallback(completion)
} else {
let group = RequestGroup(url: url)
let request = group.addCallback(completion)
group.run { (data) in
try? self.cache.setObject(data, forKey: key)
let group = RequestGroup(url: url) { (data) in
if let data = data {
try? self.cache.setObject(data, forKey: key)
}
self.groups.removeValue(forKey: url)
}
groups[url] = group
let request = group.addCallback(completion)
group.run()
return request
}
}
@ -61,29 +65,30 @@ class ImageCache {
}
func cancelWithoutCallback(_ url: URL) {
requests[url]?.cancelWithoutCallback()
groups[url]?.cancelWithoutCallback()
}
class RequestGroup {
private class RequestGroup {
let url: URL
private let onFinished: (Data?) -> Void
private var task: URLSessionDataTask?
private var requests = [Request]()
init(url: URL) {
init(url: URL, onFinished: @escaping (Data?) -> Void) {
self.url = url
self.onFinished = onFinished
}
deinit {
task?.cancel()
}
func run(cache: @escaping (Data) -> Void) {
func run() {
task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
guard error == nil, let data = data else {
self.complete(with: nil)
return
}
cache(data)
self.complete(with: data)
})
task!.resume()
@ -123,11 +128,12 @@ class ImageCache {
callback(data)
}
}
self.onFinished(data)
}
}
class Request {
weak var group: RequestGroup?
private weak var group: RequestGroup?
private(set) var callback: ((Data?) -> Void)?
private(set) var cancelled: Bool = false

View File

@ -16,20 +16,8 @@ class ProfileTableViewController: EnhancedTableViewController {
var accountID: String!
var pinnedStatuses: [(id: String, state: StatusState)] = [] {
didSet {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
var timelineSegments: [[(id: String, state: StatusState)]] = [] {
didSet {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
var pinnedStatuses: [(id: String, state: StatusState)] = []
var timelineSegments: [[(id: String, state: StatusState)]] = []
var older: RequestRange?
var newer: RequestRange?
@ -124,6 +112,12 @@ class ProfileTableViewController: EnhancedTableViewController {
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
self.pinnedStatuses = statuses.map { ($0.id, .unknown) }
let indexPaths = (0..<statuses.count).map { IndexPath(row: $0, section: 1) }
DispatchQueue.main.async {
UIView.performWithoutAnimation {
self.tableView.insertRows(at: indexPaths, with: .none)
}
}
}
}
@ -135,6 +129,12 @@ class ProfileTableViewController: EnhancedTableViewController {
self.older = pagination?.older
self.newer = pagination?.newer
DispatchQueue.main.async {
UIView.performWithoutAnimation {
self.tableView.insertSections(IndexSet(integer: 2), with: .none)
}
}
}
}
}