swiftuidrag-and-dropnsitemprovider

SwiftUI: Not getting dropped NSString value in DropDelegate


I'm trying to implement a simple drag and drop with NSString. I can get this working with NSURL but not NSString. Every time I try the drag and drop I always end up with a nil value. Here is my code:

struct ContentView: View 
{

    var body: some View 
    {
        Text("Hello World")
            .onDrag { NSItemProvider(object: "Hello World" as NSString) }
    }
}

Then the dropped object:

struct DroppedView: View, DropDelegate
{
    var body: some View 
    {
        Text("Drop here")
            .onDrop(of: ["public.text"], delegate: self)
    }

    func performDrop(info: DropInfo) -> Bool
    {
         if let items = info.itemProviders(for: ["public.text"]).first
         {
             item.loadItem(forTypeIdentifier: "public.text", options: nil)
             {
                 (data, error) in
                
                 print(data)
             }
         }
         return true
    }
}

I would have expected the output to be "Hello World". What am I missing?


Solution

  • I don't recall where (somewhere in depth of Apple's docs) but I met occasionally that we should not use base UTTypes (like public.text) for data loading - instead only concrete types (like in this answer) must be used.

    The NSString register itself as UTF-8 plain text type provider (it conforms to public.text but cannot be decoded to), so worked variant is

    func performDrop(info: DropInfo) -> Bool
    {
        if let item = info.itemProviders(for: ["public.utf8-plain-text"]).first
        {
            item.loadItem(forTypeIdentifier: "public.utf8-plain-text", options: nil)
            {
                (data, error) in
                if let data = data as? Data {
                    print(NSString(data: data, encoding: 4) ?? "failed")
                }
            }
        }
        return true
    }
    

    Tested with Xcode 13 / macOS 11.5.2

    demo