Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

onDrop() modifier with multiple UTTypes giving the least helpful one?

Hey folks

I'm trying to use .onDrop() on a view that needs to accept files. This works fine, I specify a supportedContentTypes of [.fileURL] and it works great.

I got a request to add support for dragging the macOS screenshot previews into my app and when I looked at it, they aren't available as a URL, only an image, so I changed my array to [.fileURL, .image].

As soon as I did that, I noticed that dragging any image file, even from Finder, calls my onDrop() closure with an NSItemProvider that only knows how to give me an image, with no suggestedName.

Am I missing something here? I had been under the impression that:

  1. The order of my supportedContentTypes indicates which types I prefer (although I now can't find this documented anywhere)
  2. Where an item could potentially vend multiple UTTypes, the resulting NSItemProvider would offer up the union of types that both it, and I, support.

If it helps, I put together a little test app which lets you select which UTTypes are in supportedContentTypes and then when a file is dragged onto it, it'll tell you which content types are available - as far as I can tell, it's only ever one, and macOS strongly prefers to send me an image vs a URL.

Is there anything I can do to convince it otherwise?

Answered by DTS Engineer in 841052022

In your sample project you had:

 FileRepresentation(importedContentType: .fileURL) { url in
            print("Using file representation for: \(url.file)")
            return File(url: url.file)
        }

        // If this DataRepresentation isn't commented out, Finder will always choose this for image files
        DataRepresentation(importedContentType: .image) { data in
            print("FAILURE, we got data instead of a file URL: \(data)")
            return File(url: URL(fileURLWithPath:"/tmp/FAILRE"))
        }

Depending on the content type for example public.png. which is of subclass public.image. The system will use the DataRepresentation which supports image content type and not FileRepresentation because the dropped item is not of type public.file-url.

If you used FileRepresentation(importedContentType: .image) then the system would vend the image as a file URL.

I would suggest you review Choosing a transfer representation for a model type to learn about the various transfer representations.

The order of my supportedContentTypes indicates which types I prefer (although I now can't find this documented anywhere)

This holds true for Transferable items. What’s important to remember is;

You specifier the representation in order of preference to ensure the system uses the most suitable representation, depending on the content type that the receiver can accept for drag-and-drop operations.

For example, if you had a representation like this:

    static var transferRepresentation: some TransferRepresentation {
        FileRepresentation(importedContentType: .fileURL) { url in
            try await DropItem(importing: url.file, contentType: .url)
        }

        DataRepresentation(contentType: UTType.image) { image in
            image.data
        } importing: { data in
            return DropItem.data(data)
        }
    }

if the the dragged item is of type public.heic, which also conforms to UTTypeImage, the system would use the DataRepresentation because the item isn’t of type public.file-url

You can review Making a view into a drag source and Adopting drag and drop using SwiftUI for more concrete examples and to learn more about drag and drop.

To summarise some of my replies outside the 500 character limit...

Here is another sample project:

https://github.com/cmsj/SwiftUITransferableOrderWrong

This uses Transferable, and declares it can import three different ways, a ProxyRepresentation for URL, a FileRepresentation, or a DataRepresentation.

Drag some files in from Finder:

  1. Non-image files use the ProxyRepresentation and work fine
  2. If the Proxy is commented out, those non-image files use the FileRepresentation and the provided URL is nonsense.
  3. If the DataRepresentation is not commented out, no matter which of the other two are present first, drags of image files from Finder will always choose the DataRepresentation.

Surely this has to be a bug?

Accepted Answer

In your sample project you had:

 FileRepresentation(importedContentType: .fileURL) { url in
            print("Using file representation for: \(url.file)")
            return File(url: url.file)
        }

        // If this DataRepresentation isn't commented out, Finder will always choose this for image files
        DataRepresentation(importedContentType: .image) { data in
            print("FAILURE, we got data instead of a file URL: \(data)")
            return File(url: URL(fileURLWithPath:"/tmp/FAILRE"))
        }

Depending on the content type for example public.png. which is of subclass public.image. The system will use the DataRepresentation which supports image content type and not FileRepresentation because the dropped item is not of type public.file-url.

If you used FileRepresentation(importedContentType: .image) then the system would vend the image as a file URL.

I would suggest you review Choosing a transfer representation for a model type to learn about the various transfer representations.

onDrop() modifier with multiple UTTypes giving the least helpful one?
 
 
Q