Swift 4:NSFilenamesPboardType 不可用。用啥代替 registerForDraggedTypes?

Posted

技术标签:

【中文标题】Swift 4:NSFilenamesPboardType 不可用。用啥代替 registerForDraggedTypes?【英文标题】:Swift 4: NSFilenamesPboardType not available. What to use instead for registerForDraggedTypes?Swift 4:NSFilenamesPboardType 不可用。用什么代替 registerForDraggedTypes? 【发布时间】:2017-11-16 04:02:03 【问题描述】:

迁移到 Swift4 后,以下代码引发编译错误:

public final class MediaItemView: NSView 

   public override init(frame frameRect: NSRect) 
      super.init(frame: frameRect)

      // error: 'NSFilenamesPboardType' is unavailable in Swift:
      // use 'NSPasteboard.writeObjects(_:)' with file URLs
      let draggedTypes: [NSPasteboard.PasteboardType] = [NSFilenamesPboardType]
      registerForDraggedTypes(draggedTypes)
   

Swift4 中NSFilenamesPboardType 的替代品是什么?如何在 Swift4 中注册 file name 的拖动类型(在我的情况下为 mp3、wav、aiff、... 文件)?

谢谢!

【问题讨论】:

【参考方案1】:

我已经解决了与此扩展的向后兼容性问题:

extension NSPasteboard.PasteboardType 

    static let backwardsCompatibleFileURL: NSPasteboard.PasteboardType = 

            if #available(OSX 10.13, *) 
                return NSPasteboard.PasteboardType.fileURL
             else 
                return NSPasteboard.PasteboardType(kUTTypeFileURL as String)
            

     ()


这意味着你可以使用NSPasteboard.PasteboardType.backwardsCompatibleFileURL

【讨论】:

嗯。它对我来说效果不佳,我无法获得正确的拖动文件名;取而代之的是Optional(file:///.file/id=6571367.2747208)。 Hack-ish @slboat 解决方案效果更好。 @TomekCejner 我得到了相同类型的字符串(可能与沙盒有关),但是一旦您将它们转换为带有URL(string:) 的 URL,它们就可以正常工作。然后absoluteString 方法会为您提供正常的文件系统路径。【参考方案2】:

我用这个作为解决方案

    //Temp solution for this
    let NSFilenamesPboardTypeTemp = NSPasteboard.PasteboardType("NSFilenamesPboardType")

    self.zipView.registerForDraggedTypes([NSFilenamesPboardTypeTemp])

这似乎是苹果的一个错误,他们将 api 标记为仅在 10.13 中工作。

【讨论】:

我也这样做了。看起来很危险,但对我有用。 #yolo 使用这种类型注册似乎在 10.13 中有效,但从粘贴板读取失败并显示“'NSFilenamesPboardType' 不是有效的 UTI 字符串。无法读取无效 UTI 的数据。” Mark Bridges 使用kUTTypeFileURL 的回答效果很好。【参考方案3】:

我喜欢这里为已弃用的变量 NSFilenamesPboardType 提供的创造性解决方法。在研究了这个问题之后,一种推进等效的非弃用方法的方法是使用readObjects(forClasses:options:)。这也将使 WRT 能够在未来的 macOS 上运行更安全。它将像以下示例一样实现,使用 Swift 4.1 进行测试,基于在情节提要中注册 NSView

override func awakeFromNib()

    registerForDraggedTypes([.fileURL])


override func draggingEnded(_ sender: NSDraggingInfo)

    sender
        .draggingPasteboard()
        .readObjects(forClasses: [NSURL.self],
                     options: nil)?
        .forEach
        
            // Do something with the file paths.
            if let url = $0 as? URL  print(url.path) 
        

由于readObjects 的类数组参数是[AnyClass] 类型,这就是使用NSURL 而不是URL 的原因。

【讨论】:

这应该是公认的答案。适用于 Swift 5.x。这是迄今为止我发现的唯一一个可以处理多个文件被删除的解决方案。【参考方案4】:

我也遇到了同样的问题,我的解决方案是使用kUTTypeURL 创建一个自定义NSPasteboard.PasteboardType。我不确定这是否是最合适的方法(我想不是),但它至少适用于临时解决方法。

    let draggedType = NSPasteboard.PasteboardType(kUTTypeURL as String)
    self.tableView?.registerForDraggedTypes([draggedType])

此外,新的NSPasteboard.PasteboardType 具有.fileNameType(forPathExtension: "foo") 方法。你应该试一试。但是不知何故,它在我的情况下不起作用。

【讨论】:

作为解决方法,也可以这样做:NSPasteboard.PasteboardType("NSFilenamesPboardType")【参考方案5】:

结合使用Mark Bridges' answer 和slboat's answer,这是我想出的解决方案:

extension NSPasteboard.PasteboardType 

    /// The name of a file or directory
    static let fileName: NSPasteboard.PasteboardType = 
        return NSPasteboard.PasteboardType("NSFilenamesPboardType")
    ()

这在我的测试中按预期工作。

【讨论】:

【参考方案6】:

Swift4、Swift5

部分临时解决方法,但适用于 Swift4/5:

var chromeType: NSPasteboard.PasteboardType  return NSPasteboard.PasteboardType.init(rawValue: "org.chromium.drag-dummy-type") 
var finderNode: NSPasteboard.PasteboardType  return NSPasteboard.PasteboardType.init(rawValue: "com.apple.finder.node") 
var fileURLs: NSPasteboard.PasteboardType  return NSPasteboard.PasteboardType.init(rawValue: "NSFilenamesPboardType") 
var webarchive: NSPasteboard.PasteboardType  return NSPasteboard.PasteboardType.init(rawValue: "com.apple.webarchive") 

然后聚合为

var acceptableTypes: Set<NSPasteboard.PasteboardType>  return [.URL, .fileURL, .pdf, .png, .rtf, .rtfd, .tiff, finderNode, webarchive] 

然后在视图中使用确实加载方法:

//  Intercept drags
registerForDraggedTypes(Array(acceptableTypes))

【讨论】:

【参考方案7】:

Swift 5

//MARK:- Managing a Dragging Session After an Image Is Released

    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool 
        let fetched = sender.draggingPasteboard.readObjects(forClasses:  [NSURL.self], options: nil)?
            .map( (argv) -> String? in
                guard let url = argv as? URL else
                    return nil
                
                return url.path
            ).compactMap($0)

        guard let result = fetched else
            return false
        
        // handle the result
        print(result)
        return true
    

【讨论】:

以上是关于Swift 4:NSFilenamesPboardType 不可用。用啥代替 registerForDraggedTypes?的主要内容,如果未能解决你的问题,请参考以下文章

swift Swift 4.2枚举示例

swift Swift 4.1枚举示例

swift Swift - CloudKit订阅 - 4

将 Swift 3 升级到 4,目标 c 中不再有 swift 扩展

使用 Swift 4.0.3 编译的模块不能被 Swift 4.2.1 编译器导入

swift 状态栏背景颜色在swift 4中