Download Images From A Remote URL In Swift

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:

  1. Loads an image from the cache if the image exists in the cache
  2. 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
}