Skip to content

Instantly share code, notes, and snippets.

@dbonates
Last active December 14, 2021 01:00
Show Gist options
  • Save dbonates/79d0367a4e1940b91348e4b82bd346bb to your computer and use it in GitHub Desktop.
Save dbonates/79d0367a4e1940b91348e4b82bd346bb to your computer and use it in GitHub Desktop.
A tiny and still kinda work in progress Image Cache along with convenient loader class DataService
//
// ImageCache.swift
// HMTestApp
//
// Created by Daniel Bonates on 05/12/21.
// Modified by Daniel Bonates on 05/12/21.
import UIKit
final class ImageCache {
private static let appImageFolder = "images"
private static var cacheURL: URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("cache")
}
static func getImage(for url: URL, completion: @escaping (UIImage?) -> ()) throws {
let destinationPath = cacheURL.appendingPathComponent(url.lastPathComponent)
if FileManager.default.fileExists(atPath: destinationPath.path) {
if let image = UIImage(contentsOfFile: destinationPath.path) {
completion(image)
return
} else {
throw APIError.invalidData
}
}
let imgResource = Resource<UIImage>(request: URLRequest(url: url), parse: { data in
let destinationURL = cacheURL.appendingPathComponent(url.lastPathComponent)
try? FileManager.default.createDirectory(
atPath: self.cacheURL.path,
withIntermediateDirectories: true,
attributes: [:])
do {
try data.write(to: destinationURL)
} catch let error {
print(error.localizedDescription)
}
return UIImage(data: data)
})
WebService.load(resource: imgResource, completion: { image in
completion(image)
})
}
// util - clear the cache
static func clearCache() {
let fileManager = FileManager.default
var isDir = ObjCBool(false)
guard fileManager.fileExists(atPath: cacheURL.path, isDirectory: &isDir) else {
print("nothing to clear")
return
}
do {
let files = try fileManager.contentsOfDirectory(atPath: cacheURL.path)
for file in files {
try fileManager.removeItem(atPath: cacheURL.path + "/" + file)
}
} catch let error as NSError {
print("Could not clear temp folder: \(error.debugDescription)")
}
}
}
//
// ImageCache.swift
// Listing0
//
// Created by Daniel Bonates on 05/03/17.
// Copyright © 2017 Daniel Bonates. All rights reserved.
//
import Cocoa
final class ImageCache {
private static let appImageFolder = "images"
private static var cacheURL: URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("cache")
}
static func getImage(for url: URL, completion: @escaping (NSImage?) -> ()) throws {
let destinationPath = cacheURL.appendingPathComponent(url.lastPathComponent)
if FileManager.default.fileExists(atPath: destinationPath.path) {
if let image = NSImage(contentsOfFile: destinationPath.path) {
completion(image)
return
} else {
throw APIError.invalidData
}
}
let imgResource = Resource<NSImage>(request: URLRequest(url: url), parse: { data in
let destinationURL = cacheURL.appendingPathComponent(url.lastPathComponent)
try? FileManager.default.createDirectory(
atPath: self.cacheURL.path,
withIntermediateDirectories: true,
attributes: [:])
do {
try data.write(to: destinationURL)
} catch let error {
print(error.localizedDescription)
}
return NSImage(data: data)
})
WebService.load(resource: imgResource, completion: { image in
completion(image)
})
}
// util - clear the cache
static func clearCache() {
let fileManager = FileManager.default
var isDir = ObjCBool(false)
guard fileManager.fileExists(atPath: cacheURL.path, isDirectory: &isDir) else {
print("nothing to clear")
return
}
do {
let files = try fileManager.contentsOfDirectory(atPath: cacheURL.path)
for file in files {
try fileManager.removeItem(atPath: cacheURL.path + "/" + file)
}
} catch let error as NSError {
print("Could not clear temp folder: \(error.debugDescription)")
}
}
}
//
// WebService.swift
// Listing0
//
// Created by Daniel Bonates on 05/03/17.
// Copyright © 2017 Daniel Bonates. All rights reserved.
//
import Foundation
enum APIError: Error {
case invalidURL
case invalidData
case invalidResponseFormat
case unknown
var errorMessage: String {
switch self {
case .invalidURL:
return "invalid URL"
case .invalidData:
return "no data or invalid format to decode"
case .invalidResponseFormat:
return "response format unexpected"
case .unknown:
return "network error, not known"
}
}
}
struct Resource<T> {
var request: URLRequest
var parse: (Data) -> T?
}
final class WebService {
static func load<T>(resource: Resource<T>, completion: @escaping (T?) -> ()) {
(URLSession.shared.dataTask(with: resource.request, completionHandler: { data, response, error in
guard error == nil else { print(error.debugDescription); return }
guard
let response = response as? HTTPURLResponse,
response.statusCode == 200
else {
print("request failed.")
return
}
guard let data = data else { completion(nil); return }
completion(resource.parse(data))
})).resume()
}
}
@dbonates
Copy link
Author

TODO: this cache system could be upgraded and work as storage for any type. For download videos for offline viewing, for example. This could be accomplished by implementing a justDownload kind of function, with a Bool to return the status of the operation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment