将图片拖到另一个应用程序时,filePromiseProvider writePromiseTo URL不起作用

时间:2019-03-07 18:27:46

标签: swift macos cocoa macos-mojave nsfilepromiseprovider

我在Cocoa应用程序中实现了文件承诺,该文件允许从视图中拖动图像并将其拖放到计算机上的文件夹或预览或Evernote之类的应用程序中。过去,使用NSDraggingSource委托和'namesOfPromisedFilesDropped'方法可以很好地解决这一问题。此方法将返回放置位置,并允许我直接在其中写入图像数据。因此,当拖放到诸如预览之类的应用程序图标或诸如Evernote之类的应用程序内时,文件将被写入,并且该应用程序将被加载或图像将仅显示在其中。

不幸的是,此方法在10.13中已弃用,因此在新的OS版本中不再调用该方法。相反,我已经切换到使用“ NSFilePromiseProviderDelegate”委托的filePromiseProvider writePromiseTo url方法。调用此方法,并处理图像数据。我获得了目标URL,并尝试将图像数据写入此位置。只需将其拖到Mac上的文件夹中,此方法即可正常工作。但是,当拖动到其他应用程序图标(如Preview.app)或直接拖动到Evernote中的文件夹时,出现错误'Error Domain = NSPOSIXErrorDomain Code = 2“ No such file or directory”“。

我已经尝试使用完整的URL和URL路径。无论哪种情况,当拖动到其他应用程序时,它都根本不允许在该位置拖放或创建文件。

是否可能缺少某些权利?我什至尝试使用相同的错误在这里找到Apple源代码:File Promises Source

这是我现在正在使用的代码,它返回错误且无法写入外部应用程序位置。这仅适用于拖动到计算机上的文件夹。

extension DragDropContainerView: NSFilePromiseProviderDelegate {
    internal func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, fileNameForType fileType: String) -> String {
        let fileName = NameFormatter.getFormattedNameFromDate() + "." + fileType.getFileType().typeIdentifier
        return fileName
    }

    internal func operationQueue(for filePromiseProvider: NSFilePromiseProvider) -> OperationQueue {
        return workQueue
    }

    internal func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, writePromiseTo url: URL, completionHandler: @escaping (Error?) -> Void) {
        if let snapshot = filePromiseProvider.userInfo as? SnapshotItem {
            if let data = snapshot.representationData {
                do {
                    try data.write(to: url)
                    completionHandler(nil)
                } catch {
                    completionHandler(error)
                }
            }
        }
    }
}

在这个问题上的任何帮助都将非常有用。最终,我只是希望能够将图像拖到一个应用程序中,并让该应用程序接受该拖动。这曾经有用,但是不再有用。

更新1: 经过广泛的实验,我设法找到了可行的“解决方案”。我不知道为什么会这样,但是有些最终会引发启动旧的“弃用”方法的流程。

我创建了被拖动的项目;

let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardWriter(forImageCanvas: self))
                    draggingItem.setDraggingFrame(screenshotImageView.frame, contents: draggingImage)
                    beginDraggingSession(with: [draggingItem], event: event, source: self)

这将调用以下方法;

private func pasteboardWriter(forImageCanvas imageCanvas: DragDropContainerView) -> NSPasteboardWriting {
    let provider = FilePromiseProvider(fileType: kUTTypeJPEG as String, delegate: self)
    provider.userInfo = imageCanvas.snapshotItem
    return provider
}

这将使用下面的子类设置自定义文件Promise会话。如您所见,我在这里没有处理任何逻辑,它似乎做得很少或什么都没有做。作为一项额外的测试,以验证它的作用不是很大,我将粘贴板类型设置为“音频”。我正在拖动图像而不是音频,但是它仍然可以工作。

public class FilePromiseProvider : NSFilePromiseProvider {
   public override func writableTypes(for pasteboard: NSPasteboard)
    -> [NSPasteboard.PasteboardType] {

        return [kUTTypeAudio as NSPasteboard.PasteboardType]
   }

   public override func writingOptions(forType type: NSPasteboard.PasteboardType,
                                    pasteboard: NSPasteboard)
    -> NSPasteboard.WritingOptions {
        return super.writingOptions(forType: type, pasteboard: pasteboard)
   }
}

只要实现了上述方法,它显然就会启动一个流程,该流程最终将调用下面的“已弃用”方法。此方法在Mojave中每次都能完美地工作,表明NSFilePromises API必须存在问题。如果此方法有效,则该文件承诺API应该相同,但不起作用;

override func namesOfPromisedFilesDropped(atDestination dropDestination: URL) -> [String]?

一旦该方法被调用,一切都将在Mojave中完美地运行,以将其拖到扩展坞中的应用程序图标上并直接拖入Evernote之类的应用程序中,使该应用程序恢复到以前在以前的OS版本中使用的100%拖放功能!

我的文件承诺委托仍然存在,但如下所示。如您所见,它不再执行任何操作。但是仍然需要。

extension DragDropContainerView: NSFilePromiseProviderDelegate {
   func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, fileNameForType fileType: String) -> String {
       return ""
   }

   func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, writePromiseTo url: URL, completionHandler: @escaping (Error?) -> Void) {

   }
}

任何对此“解决方案”的评论都会很棒。任何有关如何更好地做到这一点的建议也将受到欢迎。请注意,根据Apple的说法,使用File Promises API“不能保证文件会及时写入”。但是,有了上述内容,Mojave中就以某种方式调用了旧的不推荐使用的方法,并且每次都可以完美地工作。

谢谢

0 个答案:

没有答案