QLThumbnailGenerator doesn't work

I tried using QLThumbnailGenerator in Simulator for iOS and iPadOS, but it won't work at all.

All I receive is an error:



QLUbiquitousItemFetcher: could not create sandbox wrapper. Error: Error Domain=NSPOSIXErrorDomain Code=22 "couldn't issue sandbox extension com.apple.quicklook.readonly for 'path-to-file': Invalid argument" UserInfo={NSDescription=couldn't issue sandbox extension com.apple.quicklook.readonly for 'path-to-file': Invalid argument} #PreviewItem



On the actual device (at least on iPadOS), it works the first time the app is launched, then it doesn't anymore, returning a "The file couldn't be opened" error.


Am I doing something wrong, or is this a known issue?



All I do is use QLThumbnailGenerationRequest and QLThumbnailGenerator's -generateBestRepresentationForRequest:

Replies

Still the same in iOS 13 and iPadOS 13 b6.

still present in b7.

Am I the only one seeing this?

I'm not seeing exactly what you are seeing but I found your post because it's the only one I can find on QLThumbnailGenerator.


I'm running it on a device and I get the following error:

Optional(Error Domain=NSPOSIXErrorDomain Code=20 "couldn't issue sandbox extension com.apple.app-sandbox.read for '/private/var/mobile/Library/LiveFiles/com.apple.filesystems.userfsd/UNTITLED/videos/20190812.mp4': Not a directory"


Still trying to figure out why it wants my URL to point to a directory.

I figured out what the issue is in my case, but I also think I understand the way it works a little better. In my case, I was enumerating the files using FileManager.default.enumerator and the URLs were being returned with a / on the end. There is probably a way to get the enumerator to return file URLs without the / (I haven't looked into it yet). If I do this little trick:


let filename = url.lastPathComponent

let folderURL = url.deletingLastPathComponent()

let fileURL = folderURL.appendingPathComponent(filename, isDirectory: false)


then the fileURL doesn't contain a / on the end and QLThumbnailGenerator doesn't report that it expected a folder.


HOWEVER....


I still get errors in my QLThumbnailGenerator.shared.generateRepresentations which I didn't expect. I am asking for .all representations in my request because I figured it would call back every time it got a better representation of the file. The first time it calls back I get this error: Optional(Error Domain=QLThumbnailErrorDomain Code=2 "No cached thumbnail")


If called a second time on the same file URL after a success it returns: Error Domain=NSCocoaErrorDomain Code=4865 "requested key: 'root'" UserInfo={NSDebugDescription=requested key: 'root'}


In both cases, it also calls back and returns the thumbnail without error. My solution is to ignore the error and only use the image if it comes back, otherwise I have a placeholder image to use in case a thumbnail never comes back.


I hope that helps. The big surprise to me is that I the call would only return errors when it was never going to be able to return an image.


I am not running this in the simulator, only on a device because I am reading files off a USB drive and can't simulate that.

Thanks for this post. I didn't consider that it would return errors in addition to an image. It makes it impossible to know when the thumbnail generator is 'finished' with a request, which harms progress reporting.
All in all this API's behavior is poorly documented and I have no idea what to expect from it. There are multiple files in my iCloud Drive that it just decides to not return thumbnails for.
I am seeing the same errors you mention:
error: Optional(Error Domain=QLThumbnailErrorDomain Code=2 "No cached thumbnail")
Error Domain=NSCocoaErrorDomain Code=4865 "requested key: 'root'" UserInfo={NSDebugDescription=requested key: 'root'}


However, there are numerous files in my case that do not complete successfully with an image. (Despite being image files)

I have basically resorted to setting representation types to .thumbnail and I provide my own "preview" while it's loading. It's the only way I can show something useful and then a preview. The other problem I've found is the icon returned is bright white and really looks bad in an app supporting dark mode. By providing my own icons it looks better in dark mode.


I'm going to file a bug and hope it is either fixed before release or in an upcoming release. Until then I'm only using the .thumbnail which seems to work well on devices.

I have some news (progresses?)


@IBAction func generateDidSelect(_ sender: Any) {

    let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last
    print("DOC: \(docDir)")

    let absPath = URL(fileURLWithPath: docDir ?? "").appendingPathComponent("flowers.png").absoluteString
    //[[NSBundle mainBundle]URLForResource:@"flowers" withExtension:@"png"];
    let fileURL = URL(fileURLWithPath: absPath)
    fileURL.startAccessingSecurityScopedResource()

    let size = CGSize(width: 200, height: 200)
    let scale = UIScreen.main.scale

    let isFile = fileURL.isFile()
    let exists = FileManager.default.fileExists(atPath: fileURL.path)
    print("isFILE? \(isFile ? "YES" : "NO") exists? \(exists ? "YES" : "NO") \nFILE: \(fileURL)")

    let request = QLThumbnailGenerationRequest(fileAtURL: fileURL, size: size, scale: scale, representationTypes: QLThumbnailGenerationRequestRepresentationTypeAll)
    //request.iconMode = YES;

    QLThumbnailGenerator.shared().generateRepresentations(for: request, updateHandler: { thumbnail, type, error i

        DispatchQueue.main.async(execute: {

            print(String(format: "*** TYPE: %ld ****", Int(type)))
            let uiimage = thumbnail?.uiImage
            let cgImage = thumbnail?.cgImage

            if let uiimage = uiimage {
                print("uiimage: \(uiimage)")
            }
            if let cgImage = cgImage {
                print("cgImage: \(cgImage)")
           }

            if uiimage != nil {
                self.thumbnailImageView.image = uiimage
            }

            if error != nil {
                if let error = error {
                    print("ERROR: \(error)")
                }
                //self.thumbnailImageView.image = [UIImage imageWithContentsOfFile:fileURL.path]; // test read, works
            }
        })
    })


}


I tried with an image into the bundle.


Getting the file url with:

Bundle.main.url(forResource: "flowers", withExtension: "png")

and it magically works! ...but no with fileURLWithPath method.


But, accessing the same identical file uploaded via itunes into the Documents directory of the app i get a read error.


2019-10-01 12:41:27.167091+0200 test_thumb_obj[618:57118] DOC: /var/mobile/Containers/Data/Application/BE4A5950-5D24-4620-A1FE-B837222E8B64/Documents
2019-10-01 12:41:27.196739+0200 test_thumb_obj[618:57118] isFILE? YES exists? YES 
FILE: file:///var/mobile/Containers/Data/Application/BE4A5950-5D24-4620-A1FE-B837222E8B64/Documents/flowers.png
2019-10-01 12:41:27.233546+0200 test_thumb_obj[618:57118] *** TYPE: 0 ****
2019-10-01 12:41:27.233788+0200 test_thumb_obj[618:57118] uiimage: 
2019-10-01 12:41:27.233858+0200 test_thumb_obj[618:57118] cgImage:  (DP)
  < (kCGColorSpaceDeviceRGB)>
  width = 493, height = 640, bpc = 8, bpp = 32, row bytes = 1984 
  kCGImageAlphaPremultipliedFirst | kCGImageByteOrder32Little  | kCGImagePixelFormatPacked 
  is mask? No, has masking color? No, has soft mask? No, has matte? No, should interpolate? Yes
2019-10-01 12:41:27.234761+0200 test_thumb_obj[618:57118] *** TYPE: 1 ****
2019-10-01 12:41:27.234836+0200 test_thumb_obj[618:57118] uiimage: (null)
2019-10-01 12:41:27.234865+0200 test_thumb_obj[618:57118] cgImage: (null)
2019-10-01 12:41:27.234943+0200 test_thumb_obj[618:57118] ERROR: Error Domain=QLThumbnailErrorDomain Code=2 "No cached thumbnail"
2019-10-01 12:41:27.262228+0200 test_thumb_obj[618:57118] *** TYPE: 2 ****
2019-10-01 12:41:27.262317+0200 test_thumb_obj[618:57118] uiimage: (null)
2019-10-01 12:41:27.262349+0200 test_thumb_obj[618:57118] cgImage: (null)
2019-10-01 12:41:27.262452+0200 test_thumb_obj[618:57118] ERROR: Error Domain=QLThumbnailErrorDomain Code=0 "Could not generate a thum
bnail" UserInfo={NSUnderlyingError=0x281676940 {Error Domain=NSCocoaErrorDomain Code=256 "The file couldn’t be opened."}}

The only image a get i TYPE = 0, the white empty one.


And, as before, on simulator nothing good....


Error Domain=NSPOSIXErrorDomain Code=22 "couldn't issue sandbox extension com.apple.app-sandbox.read for...


Some test i missed to make it working?

Solved on iOS 13.2 beta.