В основном я создаю приложение, которое будет использовать данные из остальных API.
В его данных также есть пара изображений, которые пришли в качестве URL для загрузки. Таким образом, я думаю, что было бы лучше загрузить эти изображения только один раз, затем я кеширую их для повторного использования в моих ячейках UITableView и так далее.
Что я должен сделать, чтобы правильно использовать эту функцию?
Итак, начнем. Сначала я создал следующий класс для обработки изображений загрузки / кэширования:
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
}
}
Однако после запуска приложения я получил следующий результат:
Похоже, что все кэшированные изображения пришли до того, как я получил результат от API на ViewDidLoad
Если я прокручиваю вниз и снова вверх, я получаю следующий результат:
Кажется, все как-то «переупорядочено», тогда все выглядит хорошо.
Дополнительные классы:
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?
}