You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确处理onDrop事件?解决Core Foundation拖拽崩溃问题

解决Core Foundation拖拽崩溃:粘贴板项目与拖拽图像不匹配

问题分析

崩溃报错明确指向粘贴板项目数量与拖拽图像数量不匹配,结合代码来看,触发问题的核心原因包括:

  • 重复定义DragInfo结构体,导致编译/逻辑混乱
  • onDrag中使用了Tools枚举未定义的.furniture值
  • NSItemProvider初始化不规范,可能传入nil数据或无效类型标识符
  • 未实现对应的onDrop处理逻辑,拖拽释放时系统无法正确收尾

分步解决方案

1. 修复基础代码错误

  • 删除重复的DragInfo结构体,只保留一份
  • 若需要使用.furniture,在Tools枚举中添加该case;否则替换为已定义的.circle/.square
  • 为DragInfo补充CodingKeys枚举,确保JSON编解码正常执行

修正后的枚举和结构体代码:

enum Tools: String, Codable {
    case circle, square, furniture // 按需添加枚举值

    init(from decoder: Decoder) throws {
         let container = try decoder.singleValueContainer()
         let rawValue = try container.decode(String.self)
         self = Tools(rawValue: rawValue) ?? .circle
    }
}

struct DragInfo: Codable {
    let tool: Tools
    let url: URL

    init(_ tool: Tools, _ url: URL) {
        self.tool = tool
        self.url = url
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        tool = try container.decode(Tools.self, forKey: .tool)
        url = try container.decode(URL.self, forKey: .url)
    }

    // 必须定义CodingKeys,否则JSON解码会失败
    enum CodingKeys: String, CodingKey {
        case tool, url
    }
}

2. 规范onDrag逻辑

确保NSItemProvider的初始化可靠:

  • 避免使用try?直接忽略编码错误,添加兜底逻辑
  • 使用合法的自定义UTI类型(比如com.yourapp.draginfo),不要用模糊的xxx
  • 确保传入的数据非nil,编码失败时返回空的NSItemProvider

修正后的onDrag代码:

.onDrag {
    // 使用枚举中存在的case,URL建议使用合法路径
    let draggedData = DragInfo(.circle, URL(fileURLWithPath: "/valid/path/to/abc.txt"))
    guard let data = try? JSONEncoder().encode(draggedData) else {
        print("Failed to encode drag data")
        return NSItemProvider()
    }
    print("onDrag: \(draggedData)")
    // 使用NSData包装JSON数据,初始化ItemProvider
    return NSItemProvider(object: data as NSData, typeIdentifier: "com.yourapp.draginfo")
}

3. 实现完整onDrop处理

必须在目标视图上添加onDrop修饰符,处理拖拽数据:

// 给需要接收拖拽的视图添加onDrop
.onDrop(of: ["com.yourapp.draginfo"], delegate: DragDropDelegate())

对应的DropDelegate实现:

class DragDropDelegate: DropDelegate {
    func performDrop(info: DropInfo) -> Bool {
        guard let itemProvider = info.itemProviders.first else { return false }
        
        itemProvider.loadDataRepresentation(forTypeIdentifier: "com.yourapp.draginfo") { data, error in
            guard let data = data, error == nil else {
                print("Failed to load drop data: \(error?.localizedDescription ?? "Unknown error")")
                return
            }
            
            DispatchQueue.main.async {
                if let dragInfo = try? JSONDecoder().decode(DragInfo.self, from: data) {
                    // 在这里处理拖拽完成后的业务逻辑
                    print("Dropped info: \(dragInfo)")
                } else {
                    print("Failed to decode drop data")
                }
            }
        }
        return true
    }
}

崩溃根源说明

当NSItemProvider传入nil数据或无效类型标识符时,系统无法在粘贴板中创建对应的项目,但拖拽的视觉反馈(图像)已经生成,导致系统检测到“粘贴板项目数≠拖拽图像数”,触发Core Foundation崩溃。修复上述代码错误后,系统能正确关联粘贴板项目与拖拽元素,崩溃即可解决。

内容的提问来源于stack exchange,提问作者Keith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 17:44:52