forked from shadowfacts/Tusker
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:
parent
36326e4469
commit
d27bddb2ca
|
@ -18,7 +18,7 @@ class ImageCache {
|
||||||
|
|
||||||
let cache: Cache<Data>
|
let cache: Cache<Data>
|
||||||
|
|
||||||
var requests = [URL: RequestGroup]()
|
private var groups = [URL: RequestGroup]()
|
||||||
|
|
||||||
init(name: String, memoryExpiry expiry: Expiry) {
|
init(name: String, memoryExpiry expiry: Expiry) {
|
||||||
let storage = MemoryStorage<Data>(config: MemoryConfig(expiry: expiry))
|
let storage = MemoryStorage<Data>(config: MemoryConfig(expiry: expiry))
|
||||||
|
@ -43,14 +43,18 @@ class ImageCache {
|
||||||
completion?(data)
|
completion?(data)
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
if let completion = completion, let group = requests[url] {
|
if let completion = completion, let group = groups[url] {
|
||||||
return group.addCallback(completion)
|
return group.addCallback(completion)
|
||||||
} else {
|
} else {
|
||||||
let group = RequestGroup(url: url)
|
let group = RequestGroup(url: url) { (data) in
|
||||||
let request = group.addCallback(completion)
|
if let data = data {
|
||||||
group.run { (data) in
|
try? self.cache.setObject(data, forKey: key)
|
||||||
try? self.cache.setObject(data, forKey: key)
|
}
|
||||||
|
self.groups.removeValue(forKey: url)
|
||||||
}
|
}
|
||||||
|
groups[url] = group
|
||||||
|
let request = group.addCallback(completion)
|
||||||
|
group.run()
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,29 +65,30 @@ class ImageCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cancelWithoutCallback(_ url: URL) {
|
func cancelWithoutCallback(_ url: URL) {
|
||||||
requests[url]?.cancelWithoutCallback()
|
groups[url]?.cancelWithoutCallback()
|
||||||
}
|
}
|
||||||
|
|
||||||
class RequestGroup {
|
private class RequestGroup {
|
||||||
let url: URL
|
let url: URL
|
||||||
|
private let onFinished: (Data?) -> Void
|
||||||
private var task: URLSessionDataTask?
|
private var task: URLSessionDataTask?
|
||||||
private var requests = [Request]()
|
private var requests = [Request]()
|
||||||
|
|
||||||
init(url: URL) {
|
init(url: URL, onFinished: @escaping (Data?) -> Void) {
|
||||||
self.url = url
|
self.url = url
|
||||||
|
self.onFinished = onFinished
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
task?.cancel()
|
task?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(cache: @escaping (Data) -> Void) {
|
func run() {
|
||||||
task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
|
task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
|
||||||
guard error == nil, let data = data else {
|
guard error == nil, let data = data else {
|
||||||
self.complete(with: nil)
|
self.complete(with: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cache(data)
|
|
||||||
self.complete(with: data)
|
self.complete(with: data)
|
||||||
})
|
})
|
||||||
task!.resume()
|
task!.resume()
|
||||||
|
@ -123,11 +128,12 @@ class ImageCache {
|
||||||
callback(data)
|
callback(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.onFinished(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Request {
|
class Request {
|
||||||
weak var group: RequestGroup?
|
private weak var group: RequestGroup?
|
||||||
private(set) var callback: ((Data?) -> Void)?
|
private(set) var callback: ((Data?) -> Void)?
|
||||||
private(set) var cancelled: Bool = false
|
private(set) var cancelled: Bool = false
|
||||||
|
|
||||||
|
|
|
@ -16,20 +16,8 @@ class ProfileTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
var accountID: String!
|
var accountID: String!
|
||||||
|
|
||||||
var pinnedStatuses: [(id: String, state: StatusState)] = [] {
|
var pinnedStatuses: [(id: String, state: StatusState)] = []
|
||||||
didSet {
|
var timelineSegments: [[(id: String, state: StatusState)]] = []
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.tableView.reloadData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var timelineSegments: [[(id: String, state: StatusState)]] = [] {
|
|
||||||
didSet {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.tableView.reloadData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var older: RequestRange?
|
var older: RequestRange?
|
||||||
var newer: RequestRange?
|
var newer: RequestRange?
|
||||||
|
@ -124,6 +112,12 @@ class ProfileTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
self.pinnedStatuses = statuses.map { ($0.id, .unknown) }
|
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.older = pagination?.older
|
||||||
self.newer = pagination?.newer
|
self.newer = pagination?.newer
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
UIView.performWithoutAnimation {
|
||||||
|
self.tableView.insertSections(IndexSet(integer: 2), with: .none)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue