Drag and Drop Question

This example is based on the latest version of Swift 6.2 for macOS.

I have several classes that cannot conform to Codable for various reasons. This, unfortunately, prevents me from using Transferable. If I serialize a class instance into a Data blob and use that for drag-and-drop, it works perfectly — the drag operation succeeds. However, the destination has no way to distinguish between different types of Data blobs.

All I’d need is a way to specify a unique identifier and type that I could reference in the drop handler to determine what kind of object I’m working with.

Being restricted to Transferable feels quite limiting when your data models can’t conform to Codable. It’s honestly frustrating. Has anyone else run into this issue? Is there a reliable workaround?

I tried creating a Transferable wrapper like this:

struct CustomObjectTransfer: Codable, Transferable
{
    var data: Data

    static var transferRepresentation: some TransferRepresentation
    {
// Cannot use '.myGreatSettings' because Main actor–isolated static property 'myGreatSettings' cannot be referenced from a nonisolated context       
CodableRepresentation(contentType: .init(exportedAs: "com.yourProject.settings"))
    }
}

extension UTType
{
    static let myGreatSettings: UTType = UTType("com.yourProject.settings")!
}

In my list view

.draggable ( CustomObjectTransfer(data: myObjectData) )

The UI correctly recognizes the item as draggable. If I misspell the exportedAs identifier, it even throws an error, confirming that the exported type is being recognized by the system.

However, the drop destination completely ignores this type:

.dropDestination(for: CustomObjectTransfer.self)
							{ items, location in
								dump(items)
								return true
							}isTargeted:
							{ isTargeted in
								myDestinationIsTargeted = isTargeted
							}

If I switch to using Data.self directly — wrapping the original object data manually — everything works. I can deserialize and validate the data as needed.

The problem arises when handling multiple custom drag types. The drop target accepts any data, regardless of its intended type. You only find out the actual type after the drop occurs, during validation — which is too late. By then, isTargeted has already turned true, making the drop appear valid to the user when it actually isn’t.

Again anyone else feel this pain? Or is there a workaround that I am missing?

Thanks for the post and apologies for the delay. I see the code, but can you produce something I can just download and run?

Do you get the same results with just the relevant code in a small test project? If so, please share a link to your test project. That'll help us better understand what's going on. If you're not familiar with preparing a test project, take a look at Creating a test project.

Albert Pascual
  Worldwide Developer Relations.

Thank you for the reply. I shared the test project to my apple support ticket that I created. The apple support ticket is Case-ID: 16525926.

Let me elaborate some more as to what I am referring too. In my app we are using polymorphism that cannot be Codable. But we need to drag and drop objects into a predefined box, label, table, etc and if we simply code everything as a data blob it works no problem. But the user will not know that the drop area for Character Names was not accepted if you dropped it on Played by drop zone.

The below "Standard Object" is shared by the other two classes. This gets ignored by Codable.

So, if you try and package them up without Codable in your own data blob, it's fine. But the drop zone cannot determine that the data blob from CharecterName is different from PlayedBy. Therefore accepts drop. You can use validation afterwards to prevent errors. But that is after the mouse pointer gives you a green + sign saying that this object belongs to this drop. Im trying to avoid this confusion on the UI.

class StandardObject
{
    var objectID : UInt32 = 0
    // standard functions and parameters shared by all objects
}
class CharecterName: StandardObject, Codable, Identifiable
{
    var firstName = ""
    var lastName = ""
    
    func getObjectData() -> Data
    {
        let encoder = JSONEncoder()
        return try! encoder.encode(self)
    }
}
class PlayedBy: StandardObject, Codable, Identifiable
{
    var firstName = ""
    var lastName = ""
    
    func getObjectData() -> Data
    {
        let encoder = JSONEncoder()
        return try! encoder.encode(self)
    }
}

I have several classes that cannot conform to Codable for various reasons. This, unfortunately, prevents me from using Transferable. If I serialize a class instance into a Data blob and use that for drag-and-drop, it works perfectly — the drag operation succeeds. However, the destination has no way to distinguish between different types of Data blobs.

What you might need here is wrapper type that wraps the data types the app wants to receive.

I recommend reviewing the documentation on Creating a transferable item for drag-and-drop operations, enabling drop interactions, and the implementation shown in Adopting Drag and Drop Using SwiftUI sample project.

The sample code demonstrates how to create a custom content type, how to represent it in various transfer representations and handle both custom and multiple data types that your app expects.

Thank you for your response. Upon reviewing your message again, I realized something that clarified the issue.

Please note that I am working with Swift 6, which enforces strict concurrency compliance. The following implementation functions as intended; however, I am still encountering an error, which I am temporarily disregarding for the time being.

struct CharacterContainer: Codable, Transferable
{
    var objectID: UInt32
    var name : String = ""

    static var transferRepresentation: some TransferRepresentation
    {
        CodableRepresentation(contentType: .characterName)
        ProxyRepresentation(exporting: \.name)
    }
}
var characterContainerArray: [CharacterContainer]
{
    return dummyCharacters.map { CharacterContainer(objectID: $0.objectID, name: "\($0.firstName) \($0.lastName)") }
}
extension UTType
{
    nonisolated(unsafe) static let characterName = UTType(exportedAs: "com.DragAndDrop.characterName")
}

Xcode is flagging the nonisolated(unsafe) declaration in the UTType extension. The reported error is:

'nonisolated(unsafe)' is unnecessary for a constant with 'Sendable' type 'UTType'; consider removing it.

However, if I remove the nonisolated(unsafe) prefix, a more severe error occurs within the transferRepresentation function:

Main actor-isolated static property 'characterName' cannot be referenced from a nonisolated context.

Given this, it appears that the current implementation is functioning as intended, although the behavior may indicate a potential compiler or concurrency bug.

Drag and Drop Question
 
 
Q