基本上,我正在构建一个应用程序,该应用程序将使用来自其余API的数据。 在数据中还存在一对作为URL下载的图像。因此,尽管最好只下载这些图像一次,然后再将其缓存以在UITableView Cells上重复使用,以此类推。 如何正确使用此功能?
所以让我们开始吧。首先,我创建了以下类来处理下载/缓存图像:
class ImageService {
static let cache = NSCache<NSString, UIImage>()
static func downloadImage(url:URL, completion: @escaping (_ image:UIImage?)->()) {
let dataTask = URLSession.shared.dataTask(with: url) { (data, response, error) in
var downloadedImage:UIImage?
if let data = data {
downloadedImage = UIImage(data: data)
}
if downloadedImage != nil {
self.cache.setObject(downloadedImage!, forKey: url.absoluteString as NSString)
}
DispatchQueue.main.async {
completion(downloadedImage)
}
}
dataTask.resume()
}
static func getImage(url:URL, completion:@escaping (_ image:UIImage?)->()) {
if let image = self.cache.object(forKey: url.absoluteString as NSString) {
completion(image)
} else {
downloadImage(url: url, completion: completion)
}
}
}
在上面的代码中,我刚刚在我的UITableView类中调用了
class TableViewController: UITableViewController {
private var articlesViewModel:ArticleViewModel?
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.showsVerticalScrollIndicator = false
self.navigationController?.navigationBar.prefersLargeTitles = true
//Call Network
Networking.getApiData(url: Networking.urlRequest) { [weak self] (articles) in
//Data from API
self?.articlesViewModel = ArticleViewModel(modelRef: articles)
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}
}
//MARK: TableView DataSource
override func numberOfSections(in tableView: UITableView) -> Int {
return 1 //Static
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.articlesViewModel?.updateTableCount() ?? 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.cellIdentifier, for: indexPath) as! TableViewCell
if let title = self.articlesViewModel?.updateTableTitleForIndex(indexpath: indexPath.row) {
cell.titleCell.text = title
}
if let description = self.articlesViewModel?.updateTableDescriptionForIndex(indexpath: indexPath.row) {
cell.descriptionCell.text = description
}
if let pictureURL = self.articlesViewModel?.updateTableImageForIndex(indexpath: indexPath.row) {
ImageService.getImage(url: URL(string: pictureURL)!) { (finalImage) in
cell.imageCell.image = finalImage
}
}
return cell
}
}
但是,运行应用程序后,我得到了以下结果: 似乎所有缓存的图像都在我从 ViewDidLoad
上的API获得结果之前出现如果我向下滚动然后再次向上滚动,则会得到以下结果: 似乎一切都“重新排序”了,那么一切看起来还不错。
其他类别:
ViewModel:
class ArticleViewModel {
static var articlesRef:[Article]!
init(modelRef:[Article]) {
ArticleViewModel.articlesRef = modelRef
}
//MARK: Functions
func updateTableCount() -> Int {
return ArticleViewModel.self.articlesRef.count
}
func updateTableTitleForIndex(indexpath:Int) -> String {
return ArticleViewModel.self.articlesRef[indexpath].title ?? ""
}
func updateTableDescriptionForIndex(indexpath:Int) -> String {
return ArticleViewModel.self.articlesRef[indexpath].description ?? ""
}
func updateTableImageForIndex(indexpath:Int) -> String {
return ArticleViewModel.self.articlesRef[indexpath].urlToImage ?? ""
}
}
网络层:
class Networking {
static var urlRequest = "https://newsapi.org/v2/everything?q=apple&from=2019-06-05&to=2019-06-05&sortBy=popularity&apiKey=04d5f33acdde48f1a22a90f46fc483b5"
static func getApiData(url: String?, _ completion:@escaping([Article]) -> ()) {
guard let unrwpUrl = url else {return}
let request = URL(string: unrwpUrl)
URLSession.shared.dataTask(with: request!) { (data, request, error) in
if let data = data {
do {
let decodedData = try JSONDecoder().decode(Articles.self, from: data)
completion(decodedData.articles)
}catch{
print(error.localizedDescription)
}
}
}.resume()
}
}
型号:
struct Articles: Decodable {
let articles:[Article]
}
struct Article: Decodable {
let title:String?
let author:String?
let description:String?
let urlToImage:String?
}