【问题标题】:Got an error when dragging files using NSEvent. (macOS)使用 NSEvent 拖动文件时出错。 (苹果系统)
【发布时间】:2021-04-28 07:09:51
【问题描述】:

我想将文件拖到我的窗口,然后执行操作。

我尝试使用下面this answer中提供的sn-ps来区分你是拖动文件还是窗口。

// In my window controller

class MyWindowController: NSWindowController {
    
    init() {
        // Some initialization steps below are omitted
        let win = NSWindow(...)
        super.init(window: win)
        
        let contentView = DropView(frame: win.frame)
        win.contentView?.addSubview(contentView)

        registerGlobalMouseEvent()
    }

    func registerGlobalMouseEvent() {
        self.window?.acceptsMouseMovedEvents = true
        
        NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
            // Codes below will cause errors
            let pasteBoard = NSPasteboard(name: .drag)
            guard let fileNames = pasteBoard.propertyList(forType: .init(rawValue: "NSFilenamesPboardType")) as? NSArray else { return }
            let changeCount = pasteBoard.changeCount

            if fileNames.count > 0 && lastChangeCount != changeCount {
                lastChangeCount = changeCount

                // My actions when dragging
            }
        })
    }
    
}

然后我运行我的代码并开始拖动,我得到了三个错误:

[沙盒] 获取沙盒扩展失败

[Framework] 无法为 /Users/roy/Downloads/test.txt 发布沙盒扩展,错误 1

[默认] 无法为 URL 颁发沙盒令牌:'file:///Users/roy/Downloads/test.txt' 错误:'Error Domain=NSPOSIXErrorDomain Code=1 "Operation not allowed" UserInfo={NSLocalizedDescription =无法为文件“/Users/roy/Downloads/test.txt”发出沙盒扩展:不允许操作}'

 

但是当我这样做的时候

NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
    // My actions
})

,然后一切顺利。

 

第一个错误似乎无害,因为它并没有阻止我的应用程序运行。

第二个和第三个是致命的,直接导致我的应用崩溃。

不知道his code有什么问题吗? 任何有用的想法都会很棒! :)


 

【问题讨论】:

    标签: swift macos


    【解决方案1】:

    在使用沙盒时,您需要了解Bookmarks and Security Scoped URLs。拖动的 URL 仅授予您的应用进程一次读取或读取/写入“用户选择的文件”的权限,具体取决于您配置权利的方式。

    您可以保存一个书签(数据块),以便在后续会话中继续访问,只要该文件没有被另一个进程更新,此时书签已过时,您需要鼓励用户选择该文件再次。

    跨 XPC 边界(如共享)将 URL 传递给另一个进程需要您拥有该文件,因此可能涉及到沙盒缓存的副本。

    例如:

    let dragurl = url_of_dragged_file //at this point you have at-least read access
    let cachepath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).last!
    let cachedir = URL(fileURLWithPath: cachepath)
    let cacheurl = cachedir
      .appendingPathComponent(UUID().uuidString)
      .appendingPathExtension(dragurl.pathExtension)
    try FileManager.default.copyItem(at: dragurl, to: cacheurl)
    

    此时,您的本地沙盒缓存中有一个副本,可以将其移交给共享表。

    【讨论】:

    • 感谢您的回答!但是,我在捕获文件的 url 时尝试保存书签,但仍然出现这些错误。以及如何“将副本保存到我的沙盒缓存”?介意进一步解释吗? :)
    • 查看编辑。保存书签还不够,在使用startAccessingSecurityScopedResource/stopAccessingSecurityScopedResource的URL时需要使用bookended调用
    • 谢谢!看来我在保存书签时遇到了一些问题。我已经更新了我的帖子,请查看上面的编辑! :)
    【解决方案2】:

    所以我终于找到了解决方案。 :)

    看来确实和我上面提到的sn-ps有关系,这里更正一下:

    NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
        let pasteboard = NSPasteboard(name: .drag)
        let changeCount = pasteboard.changeCount
        if lastChangeCount != changeCount {
            lastChangeCount = changeCount
            if pasteboard.canReadObject(forClasses: [NSURL.self], options: [:]) {
                /// actions
            }
        }
    })
    

    这样,我没有错误,我的代码运行完美!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-25
      • 2020-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-19
      相关资源
      最近更新 更多