fetchThumbnails(for:requestedSize:perThumbnailCompletionHandler:completionHandler:)
Fetches the thumbnails for items that have been enumerated by the file provider.
Declaration
func fetchThumbnails(for itemIdentifiers: [NSFileProviderItemIdentifier], requestedSize size: CGSize, perThumbnailCompletionHandler: @escaping (NSFileProviderItemIdentifier, Data?, (any Error)?) -> Void, completionHandler: @escaping ((any Error)?) -> Void) -> ProgressParameters
- itemIdentifiers:
The identifiers of the items that need thumbnails.
- size:
The size of the thumbnails, in pixels.
- perThumbnailCompletionHandler:
The completion handler for each thumbnail. Call this block once for each thumbnail returned. This completion handler takes the following parameters:
- identifier
The identifier of the item.
- imageData
A data object containing the thumbnail, or
nilif an error occurred. This data object must be in an image format supported by Imageio.- error
An error object. If an error occurs for this item, pass in an object that describes the error; otherwise, set it to
nil.
- completionHandler:
The completion handler for the entire request. Call this block after all thumbnails have been returned. This completion handler takes the following parameter:
- error
An error object. If a global error occurs, pass in an object that describes the error; otherwise, set it to
nil.
Return Value
An object that reports the progress of this request. If the thumbnails are no longer needed, the system can cancel this request by calling the progress object’s cancel() method.
Discussion
For local files, the system automatically provides thumbnails for supported content types, and calls a Quick Look Preview extension to get thumbnails for custom types.
However, the system cannot generate thumbnails for remote items. Instead, it calls this method to request thumbnails for items stored on a remote sever. The system caches these thumbnails, and only requests thumbnails for new items as they are needed. Thumbnails are cached based on the item’s versionIdentifier property. To update an item’s thumbnail, update the item’s version identifier.
In your implementation, call the perThumbnailCompletionHandler block once for each item in the itemIdentifiers array. Call the completionHandler block only after calling perThumbnailCompletionHandler for each item.
If a global error occurs, you do not have to call perThumbnailCompletionHandler on each item. Instead, call the completionHandler block, and pass in the global error. The system applies this error to all outstanding items.
If a given item does not have a thumbnail, call the perThumbnailCompletionHandler block and pass nil for both the imageData and error parameters.
Listing 1 shows an example implementation.
Listing 1. Fetching thumbnails from a remote server.
override func fetchThumbnails(for itemIdentifiers: [NSFileProviderItemIdentifier], requestedSize size: CGSize, perThumbnailCompletionHandler: @escaping (NSFileProviderItemIdentifier, Data?, Error?) -> Void, completionHandler: @escaping (Error?) -> Void) -> Progress {
let urlSession = URLSession(configuration: URLSessionConfiguration.default)
let progress = Progress(totalUnitCount: Int64(itemIdentifiers.count))
for identifier in itemIdentifiers {
// Create a request for the thumbnail from your server.
let request = myURLRequestForThumbnail(identifier: identifier, size: size)
// Download the thumbnail to disk
// For simplicity, this sample downloads each thumbnail separately;
// however, if possible, you should batch download all the thumbnails at once.
let downloadTask = urlSession.downloadTask(with: request, completionHandler: { (tempURL, response, error) in
guard progress.isCancelled != true else {
return
}
var myErrorOrNil = error
var mappedDataOrNil: Data? = nil
// If the download succeeds, map a data object to the file
if let fileURL = tempURL {
do {
mappedDataOrNil = try Data(contentsOf:fileURL, options: Data.ReadingOptions.alwaysMapped)
}
catch let mappingError {
myErrorOrNil = mappingError
}
}
// Call the per thumbnail completion handler for each thumbnail requested.
perThumbnailCompletionHandler(identifier, mappedDataOrNil, myErrorOrNil)
DispatchQueue.main.async {
if progress.isFinished {
// Call this completion handler once all thumbnails are complete
completionHandler(nil)
}
}
})
// Add the download task's progress as a child to the overall progress.
progress.addChild(downloadTask.progress, withPendingUnitCount: 1)
// Start the download task.
downloadTask.resume()
}
return progress
}