NSPasteboard 复制拖放文件

NSPasteboard Copy Dragged and Dropped File

虽然我有工作代码,但我对自己是否采用了正确的方法感到困惑NSPasteboard,我想看看是否有人可以帮助我阐明最佳方法。

自 2012 年以来,Apple 似乎没有编写任何关于拖放的完整文档,而在那个时候,似乎已经弃用并改变了您使用的方式(尤其是沙盒应用程序)应该实施它。经过一番折腾后,我发现当您访问其路径 [=35] 时,拖动的粘贴板提供的文件 URL 会显示其真实路径(与构成 url 的匿名数字字符串相反) =],这样就可以使用 FileManager 制作常规副本。

我的问题是,我在这里遵循的程序是否正确?将从粘贴板获得的 NSURL 转换为 URL 类型并在 copyItem(at:URL, to:URL) 中使用它不起作用(即使将相同的 url 复制并粘贴到 Safari 中使我能够查看文件)。因此我改用 copyItem(atPath:String, toPath:String)。为了进一步解决这一点,是否有一种方法可以将 URL 类型替换为 NSURL(from:NSPasteboard)?好像应该有。

无论如何,这是我正在使用的代码(请忽略 draggingEntered 中的代码:目前,它只是让测试工作正常,我注册 NSFilenamesPboardType 但随后忽略它的事实也可能是也被忽视了)。

import Cocoa

class DraggerView: NSView {
    let types = [NSURLPboardType, NSFilenamesPboardType]
    var directory:URL!

    override init(frame: NSRect) {
        super.init(frame: frame)
        register(forDraggedTypes: types)
        if  let dir = URL(string:NSTemporaryDirectory())
        {
            directory = dir
        }
    }


    required init?(coder: NSCoder) {
        super.init(coder: coder)
        register(forDraggedTypes: types)
        if  let dir = URL(string:NSTemporaryDirectory())
        {
            directory = dir
        }
    }

    override func draw(_ dirtyRect: NSRect)  {
        super.draw(dirtyRect)
        NSColor.white.set()
        NSRectFill(dirtyRect)
    }

    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation  {
        return NSDragOperation.copy
    }


    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {

        let pboard = sender.draggingPasteboard()
        if let types = pboard.types, types.contains(NSURLPboardType) {


            // add file name to save to loaction
            if let fileURL = NSURL(from:pboard), let filename = fileURL.lastPathComponent {
                directory.appendPathComponent(filename)
                do {
                    try FileManager.default.copyItem(atPath:fileURL.path!, toPath:directory.path)
                }
                catch {
                    // something went wrong
                }
            }


            return true
        }
        else { return false }
    }
}

最后一点是文档一直提到在注册拖动类型时使用 UTI,但我不清楚这延伸了多远。我应该用 UTI 替换 NSURLPboardTypeNSFilenamesPboardType 吗?

根据 Apple 开发者论坛上的建议,我放弃了很多代码并实现了 readObjects: 方法。这大大简化了事情。

我现在可以使用以下代码(通过使用 URL 而不是路径的首选方法)。

import Cocoa

class DraggerView: NSView {

    override init(frame: NSRect) {
        super.init(frame: frame)
        self.register(forDraggedTypes: [NSURLPboardType])
    }


    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.register(forDraggedTypes: [NSURLPboardType])
    }

    override func draw(_ dirtyRect: NSRect)  {
        super.draw(dirtyRect)
        NSColor.white.set()
        NSRectFill(dirtyRect)
    }



    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation  {
       return NSDragOperation.copy
    }


    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
        let pboard = sender.draggingPasteboard()
        if let urls = pboard.readObjects(forClasses: [NSURL.self], options: [:]) as? [URL] {
            for url in urls {
                do {
                    var directory = URL(fileURLWithPath:NSTemporaryDirectory())
                    directory.appendPathComponent(url.lastPathComponent)
                    try FileManager.default.copyItem(at:url, to:directory)
                }
                catch {
                    // something went wrong
                }

            }
        }


        return true
    }
}

注意:以上代码将任何拖放的文件或文件夹(包括文件和子文件夹)复制到您应用的临时目录。