swift NSItemProviderWriting用于将内容拖动到Finder

qv7cva1a  于 2023-01-12  发布在  Swift
关注(0)|答案(1)|浏览(257)

我正在构建一个SwiftUI视图,其中包含可拖动的内容,还有一个自定义的NSItemProviderWriting类,用于在拖动到应用程序的另一个部分时提供一种类型的数据,在拖动到Finder时提供另一种类型的数据。不过,为了拖动到Finder,我最难设置NSItemProviderWriting
首先,这是该观点的相关部分:

myView
    .onDrag {
        NSItemProvider(object: MyDragProvider("dragged text"))
    }

很简单。MyDragProvider是目前需要完成的工作:

class TestDragProvider: NSObject, NSItemProviderWriting {
    var stringValue: String

    init(_ value: String) {
        self.stringValue = value
    }

    static var writableTypeIdentifiersForItemProvider: [String] {
        let utTypes: [UTType] = [
            myCustomUTType,
            .fileUrl
        ]
        return utTypes.map { $0.identifier }
    }

    func loadData(
        withTypeIdentifier typeIdentifier: String,
        forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, Error?) -> Void
    ) -> Progress? {
        let progress = Progress(totalUnitCount: 1)
        var data: Data? = nil
        
        print("Loading data for type: \(typeIdentifier)")
        if let utType = UTType(typeIdentifier) {
            if utType == myCustomUTType {
                data = stringValue.data(using: .utf8)
            } else if utType == .fileUrl {
                let urlOfSomeFile = FileManager
                                        .default
                                        .urls(for: .cachesDirectory, in: .userDomainMask)[0]
                                        .appendingPathComponent("fileToDrag.txt")
                                        .absoluteURL
                data = try! NSKeyedArchiver.archivedData(withRootObject: (urlOfSomeFile as NSURL), requiringSecureCoding: false)
            }
        }

        progress.completedUnitCount = data != nil ? 1 : 0
        completionHandler(data, nil)
        return progress
}

当我将项目拖到应用中接收此类拖拽的另一部分时,这一功能可以正常工作(print语句输出Loading data for type: myCustomUTType),但当我尝试将项目拖到应用之外时,控制台会输出以下内容:
通过NSPasteboardWriting写入粘贴板的NSURL必须是绝对URL。NSURL“bplist00%C3%94%01%02%03%04%05%06%07%0AX$versionY$archiverT$topX$objects%12%00%01%C2%86%C2%A0_%10%0FNSKeyedArchiver%C3%91... 00%01%1B”不是绝对URL。
[沙盒]创建沙盒扩展数据失败:网址数据:0x 600000 be 9640长度:0(-1表示空)
[常规]风格public.file-url立即需要沙盒扩展数据,但无法获取。
[沙盒]创建沙盒扩展数据失败:网址数据:0x 600000 be 9640长度:0(-1表示空)
[沙盒]无法获取沙盒扩展名
我猜[sandbox][general]错误是关于权限的,但是第一个关于绝对URL的错误是混淆的。我已经尝试了几种变体,包括在urlOfSomeFile上添加或删除.absoluteURL,以及将NSKeyedArchiver切换为JSONEnconder
还有谁知道怎么度过这一关?

eqqqjvef

eqqqjvef1#

您是否尝试过向URL请求它的dataRepresentation

data = urlOfSomeFile.dataRepresentation

我测试了下面的Xcode Playground,拖动到Finder可以达到我的预期(将fileToDrag.txt移动到桌面):

import SwiftUI
import UniformTypeIdentifiers

class MyDragProvider: NSObject, NSItemProviderWriting {
  static var writableTypeIdentifiersForItemProvider: [String] {
    return [UTType.fileURL].map(\.identifier)
  }

  func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void) -> Progress? {
    switch typeIdentifier {
    case UTType.fileURL.identifier:
      let urlOfSomeFile = FileManager
        .default
        .urls(for: .cachesDirectory, in: .userDomainMask)[0]
        .appendingPathComponent("fileToDrag.txt")
        .absoluteURL
      try! String("hello world").write(to: urlOfSomeFile, atomically: true, encoding: .utf8)
      let data = urlOfSomeFile.dataRepresentation
      completionHandler(data, nil)
      return nil
    default:
      fatalError()
    }
  }
}

import PlaygroundSupport
PlaygroundPage.current.setLiveView(
  Text("Drag me")
    .padding()
    .onDrag {
      NSItemProvider(object: MyDragProvider())
    }
)

相关问题