This post presents a method to download an image from a remote URL and save the image to a file cache in Swift. If the image is already downloaded, the method will read the image directly from the cache.
Download A Remote Image From A URL To A File Cache
The URLSession.downloadTask(with:)
method will download a remote URL to a local file. The first parameter in the callback is a temporary URL to the downloaded file. This temporary file will be deleted when the callback completes, so it is important to copy the temporary file to a new location before the callback finishes.
func download(
url: URL,
toFile file: URL,
completion: @escaping (Error?) -> Void) {
// Download the remote URL to a file
let task = URLSession.shared.downloadTask(with: url) {
(tempURL, response, error) in
// Early exit on error
guard let tempURL = tempURL else {
completion(error)
return
}
do {
// Remove any existing document at file
if FileManager.default.fileExists(atPath: file.path) {
try FileManager.default.removeItem(at: file)
}
// Copy the tempURL to file
try FileManager.default.copyItem(
at: tempURL,
to: file
)
completion(nil)
}
// Handle potential file system errors
catch let fileError {
completion(error)
}
}
// Start the download
task.resume()
}
Load An Image From A Remote URL Or Cache
With a download(url:toFile:completion:)
implementation, the next step is to create an interface that:
- Loads an image from the cache if the image exists in the cache
- Otherwise downloads the image to the cache
An important consideration is where to cache images. One option is the temporary directory (read more). On Apple platforms like iOS, the temporary directory will automatically be purged in low-memory situations.
func loadImage(
url: URL,
completion: @escaping (UIImage?, Error?) -> Void) {
// Determine the cached file path of the remote url
let cachedFile = FileManager.default.temporaryDirectory
.appendingPathComponent(
url.lastPathComponent,
isDirectory: false
)
// If the image exists in the cache,
// load the image from the cache and exit
if let image = UIImage(contentsOfFile: cachedFile.path) {
completion(image, nil)
return
}
// If the image does not exist in the cache,
// download the image to the cache
download(url: url, toFile: cachedFile) { (error) in
let image = UIImage(contentsOfFile: cachedFile.path)
completion(image, error)
}
}
Downloading and Caching Images in Swift
That’s it! Using URLSession
and FileManager
you can work with remote images in Swift without any external dependencies.
// Example Usage
let url = URL(string: "https://domain.com/logo.png")!
loadImage(url: url) { (image, error) in
// Handle the loaded image
}