<!--
{
  "documentType" : "article",
  "framework" : "Foundation",
  "identifier" : "/documentation/Foundation/pausing-and-resuming-downloads",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Pausing and resuming downloads"
}
-->

# Pausing and resuming downloads

Allow the user to resume a download without starting over.

## Discussion

Your app or the user may need to cancel an in-progress download and resume it later. By supporting resumable downloads, you save both the user’s time and network bandwidth.

You can also use this technique to resume a download that fails due to a temporary loss of connectivity.

### Store the resume data object when you cancel the download

You cancel a [`URLSessionDownloadTask`](/documentation/Foundation/URLSessionDownloadTask) by calling [`cancel(byProducingResumeData:)`](/documentation/Foundation/URLSessionDownloadTask/cancel(byProducingResumeData:)). This method takes a completion handler which is called once the cancellation is complete. The completion handler receives a `resumeData` parameter. If it it not `nil`, this is the token you use later to resume the download. The following example shows how to cancel a download task and store `resumeData`, if it exists, in a property.

Storing the resume data when canceling a download

```swift
downloadTask.cancel { resumeDataOrNil in
    guard let resumeData = resumeDataOrNil else { 
      // download can't be resumed; remove from UI if necessary
      return
    }
    self.resumeData = resumeData
}
```

> Important:
> Not all downloads can be resumed. See the discussion in ``doc://com.apple.foundation/documentation/Foundation/URLSessionDownloadTask/cancel(byProducingResumeData:)`` for a list of conditions that must be met for a download to be resumable. Also, downloads that use a background configuration will handle resumption automatically, so manual resuming is only needed for non-background downloads.

### Store the resume data object when a download fails

You can also resume a download that has failed due to a temporary loss of connectivity, as when the user walks out of WiFi range.

When the download fails, the session calls your [`urlSession(_:task:didCompleteWithError:)`](/documentation/Foundation/URLSessionTaskDelegate/urlSession(_:task:didCompleteWithError:)) delegate method. If `error` is not `nil`, look in its `userInfo` dictionary for the key [`NSURLSessionDownloadTaskResumeData`](/documentation/Foundation/NSURLSessionDownloadTaskResumeData). If the key exists, save the value associated with it to use later when you try to resume the download. If the key does not exist, the download can’t be resumed.

The following example shows an implementation of [`urlSession(_:task:didCompleteWithError:)`](/documentation/Foundation/URLSessionTaskDelegate/urlSession(_:task:didCompleteWithError:)) that retrieves and saves the `resumeData` object, if any, from the error.

```swift
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    guard let error = error else {
        // Handle success case.
        return
    }
    let userInfo = (error as NSError).userInfo
    if let resumeData = userInfo[NSURLSessionDownloadTaskResumeData] as? Data {
        self.resumeData = resumeData
    } 
    // Perform any other error handling.
}
```

### Use the stored resume data object to resume downloading

When it’s appropriate to resume the download, create a new [`URLSessionDownloadTask`](/documentation/Foundation/URLSessionDownloadTask) by using the [`downloadTask(withResumeData:)`](/documentation/Foundation/URLSession/downloadTask(withResumeData:)) or [`downloadTask(withResumeData:completionHandler:)`](/documentation/Foundation/URLSession/downloadTask(withResumeData:completionHandler:)) method of [`URLSession`](/documentation/Foundation/URLSession), passing in the `resumeData` object you stored earlier. Then call [`resume()`](/documentation/Foundation/URLSessionTask/resume()) on the task to resume the download.

Creating and starting a download task from resume data

```swift
guard let resumeData = resumeData else {
    // inform the user the download can't be resumed
    return
}
let downloadTask = urlSession.downloadTask(withResumeData: resumeData)
downloadTask.resume()
self.downloadTask = downloadTask
```

If the download resumes successfully, the task calls your delegate’s [`urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)`](/documentation/Foundation/URLSessionDownloadDelegate/urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)) method. You can use the offset and byte count parameters to inform the user that the download has resumed and has preserved its earlier progress.

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)