Create and use IconImageCache. It centralizes and de-dupes logic for getting feed/article images, and it caches the results, which helps performance.

This commit is contained in:
Brent Simmons
2021-05-08 12:42:44 -07:00
parent 28b00260e0
commit 9d2c8f000f
12 changed files with 160 additions and 174 deletions

View File

@@ -248,12 +248,11 @@ private extension ActivityManager {
attributeSet.title = feed.nameForDisplay
attributeSet.keywords = makeKeywords(feed.nameForDisplay)
attributeSet.relatedUniqueIdentifier = ActivityManager.identifer(for: feed)
if let iconImage = appDelegate.webFeedIconDownloader.icon(for: feed) {
attributeSet.thumbnailData = iconImage.image.dataRepresentation()
} else if let iconImage = appDelegate.faviconDownloader.faviconAsIcon(for: feed) {
if let iconImage = IconImageCache.shared.imageForFeed(feed) {
attributeSet.thumbnailData = iconImage.image.dataRepresentation()
}
selectingActivity!.contentAttributeSet = attributeSet
selectingActivity!.needsSave = true

View File

@@ -96,32 +96,7 @@ extension Article {
}
func iconImage() -> IconImage? {
if let authors = authors, authors.count == 1, let author = authors.first {
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
return image
}
}
if let authors = webFeed?.authors, authors.count == 1, let author = authors.first {
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
return image
}
}
guard let webFeed = webFeed else {
return nil
}
let feedIconImage = appDelegate.webFeedIconDownloader.icon(for: webFeed)
if feedIconImage != nil {
return feedIconImage
}
if let faviconImage = appDelegate.faviconDownloader.faviconAsIcon(for: webFeed) {
return faviconImage
}
return FaviconGenerator.favicon(webFeed)
return IconImageCache.shared.imageForArticle(self)
}
func iconImageUrl(webFeed: WebFeed) -> URL? {

129
Shared/IconImageCache.swift Normal file
View File

@@ -0,0 +1,129 @@
//
// IconImageCache.swift
// NetNewsWire-iOS
//
// Created by Brent Simmons on 5/2/21.
// Copyright © 2021 Ranchero Software. All rights reserved.
//
import Foundation
import Account
import Articles
class IconImageCache {
static var shared = IconImageCache()
private var smartFeedIconImageCache = [FeedIdentifier: IconImage]()
private var webFeedIconImageCache = [FeedIdentifier: IconImage]()
private var faviconImageCache = [FeedIdentifier: IconImage]()
private var smallIconImageCache = [FeedIdentifier: IconImage]()
private var authorIconImageCache = [Author: IconImage]()
func imageFor(_ feedID: FeedIdentifier) -> IconImage? {
if let smartFeed = SmartFeedsController.shared.find(by: feedID) {
return imageForFeed(smartFeed)
}
if let feed = AccountManager.shared.existingFeed(with: feedID) {
return imageForFeed(feed)
}
return nil
}
func imageForFeed(_ feed: Feed) -> IconImage? {
guard let feedID = feed.feedID else {
return nil
}
if let smartFeed = feed as? PseudoFeed {
return imageForSmartFeed(smartFeed, feedID)
}
if let webFeed = feed as? WebFeed, let iconImage = imageForWebFeed(webFeed, feedID) {
return iconImage
}
if let smallIconProvider = feed as? SmallIconProvider {
return imageForSmallIconProvider(smallIconProvider, feedID)
}
return nil
}
func imageForArticle(_ article: Article) -> IconImage? {
if let iconImage = imageForAuthors(article.authors) {
return iconImage
}
guard let feed = article.webFeed else {
return nil
}
return imageForFeed(feed)
}
func emptyCache() {
smartFeedIconImageCache = [FeedIdentifier: IconImage]()
webFeedIconImageCache = [FeedIdentifier: IconImage]()
faviconImageCache = [FeedIdentifier: IconImage]()
smallIconImageCache = [FeedIdentifier: IconImage]()
authorIconImageCache = [Author: IconImage]()
}
}
private extension IconImageCache {
func imageForSmartFeed(_ smartFeed: PseudoFeed, _ feedID: FeedIdentifier) -> IconImage? {
if let iconImage = smartFeedIconImageCache[feedID] {
return iconImage
}
if let iconImage = smartFeed.smallIcon {
smartFeedIconImageCache[feedID] = iconImage
return iconImage
}
return nil
}
func imageForWebFeed(_ webFeed: WebFeed, _ feedID: FeedIdentifier) -> IconImage? {
if let iconImage = webFeedIconImageCache[feedID] {
return iconImage
}
if let iconImage = appDelegate.webFeedIconDownloader.icon(for: webFeed) {
webFeedIconImageCache[feedID] = iconImage
return iconImage
}
if let faviconImage = faviconImageCache[feedID] {
return faviconImage
}
if let faviconImage = appDelegate.faviconDownloader.faviconAsIcon(for: webFeed) {
faviconImageCache[feedID] = faviconImage
return faviconImage
}
return nil
}
func imageForSmallIconProvider(_ provider: SmallIconProvider, _ feedID: FeedIdentifier) -> IconImage? {
if let iconImage = smallIconImageCache[feedID] {
return iconImage
}
if let iconImage = provider.smallIcon {
smallIconImageCache[feedID] = iconImage
return iconImage
}
return nil
}
func imageForAuthors(_ authors: Set<Author>?) -> IconImage? {
guard let authors = authors, authors.count == 1, let author = authors.first else {
return nil
}
return imageForAuthor(author)
}
func imageForAuthor(_ author: Author) -> IconImage? {
if let iconImage = authorIconImageCache[author] {
return iconImage
}
if let iconImage = appDelegate.authorAvatarDownloader.image(for: author) {
authorIconImageCache[author] = iconImage
return iconImage
}
return nil
}
}