如何为自定义类型设置粘贴板 属性 列表 - NSPasteboard / Swift

How to set the Pasteboard Property List for a custom type - NSPasteboard / Swift

我正在开发一个 Cocoa 应用程序,用于在两个 NSTable 视图之间拖放文件。我不想只使用 URL,而是想使用自定义结构,这样我就可以在需要时访问更多数据,而不是不断调用 FileManager。

我认为我需要使我的自定义粘贴板实用程序符合 NSPasteboardReading,这样我才能正确消化接收数据 table。

我不确定在处理我在粘贴板中使用的自定义结构时,根据需要设置 init?(pasteboardPropertyList propertyList: Any, ofType type: NSPasteboard.PasteboardType) 函数到底需要什么。

坦率地说,我不确定在这种情况下如何使用 属性 列表,因为我过去通常只在设置全局应用程序 plist 时使用它。

遗憾的是,这里没有很多资源。我见过的大多数示例通常引用 属性 列表的 JSON 对象。我不确定是否需要将自定义类型中的数据提取到数据或字符串类型的数组中。

此处提供任何关于实施的指导,或者关于 属性 列表的可能性的更好指导,我们将不胜感激!

传递给粘贴板的自定义结构:

struct TidiFile {
    var url : URL?
    var createdDateAttribute : Date?
    var modifiedDateAttribute : Date?
    var fileSizeAttribute: Int?


    //setting for a nil init so this can return nil values in case of failure to set attributes
    init( url : URL? = nil,
        createdDateAttribute : Date? = nil,
        modifiedDateAttribute : Date? = nil,
        fileSizeAttribute: Int? = nil) {
        self.url = url
        self.createdDateAttribute = createdDateAttribute
        self.modifiedDateAttribute = modifiedDateAttribute
        self.fileSizeAttribute = fileSizeAttribute
    }
}

Table 视图控制器: 我将项目写入粘贴板的位置

    func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
        return PasteboardWriter(tidiFile: tableSourceTidiFileArray[row], at: row)
    }

Table 视图控制器: 我要接受拖放并移动文件的位置

func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {

            let pasteboard = info.draggingPasteboard
            let pasteboardItems = pasteboard.pasteboardItems


    }

自定义粘贴板实用程序:

import Foundation
import Cocoa

class PasteboardWriter: NSObject, NSPasteboardWriting, NSPasteboardReading {
    required init?(pasteboardPropertyList propertyList: Any, ofType type: NSPasteboard.PasteboardType) {
        // Need to implement
    }

    var tidiFile : TidiFile
    var index: Int


    init(tidiFile : TidiFile, at index: Int) {
        self.tidiFile = tidiFile
        self.index = index
    }

    func writableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] {
        return [.tableViewIndex, .tidiFile]
    }

    func pasteboardPropertyList(forType type: NSPasteboard.PasteboardType) -> Any? {
        switch type {
        case .tidiFile:
            return tidiFile
        case .tableViewIndex:
            return index
        default:
            return nil
        }
    }


    static func readableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] {
        return [.tableViewIndex, .tidiFile]
    }

}

extension NSPasteboard.PasteboardType {
    static let tableViewIndex = NSPasteboard.PasteboardType("com.bradzellman.tableViewIndex")
    static let tidiFile = NSPasteboard.PasteboardType("com.bradzellman.tidiFile")
}


extension NSPasteboardItem {
    open func integer(forType type: NSPasteboard.PasteboardType) -> Int? {
        guard let data = data(forType: type) else { return nil }
        let plist = try? PropertyListSerialization.propertyList(
            from: data,
            options: .mutableContainers,
            format: nil)
        return plist as? Int
    }
}

首先要能够拖放自定义对象,该对象必须是 NSObject.

的子class

这是非可选类型的快速实现。数据序列化到 属性 列表和 Codable。协议方法 init(from decoderencode(to encoder 被合成。

init?(pasteboardPropertyList 中,您必须解码一个实例并使用标准初始化程序创建一个新实例。

final class TidiFile : NSObject, Codable {

    var url : URL
    var createdDateAttribute : Date
    var modifiedDateAttribute : Date
    var fileSizeAttribute: Int

    init(url: URL, createdDateAttribute: Date, modifiedDateAttribute: Date, fileSizeAttribute: Int) {
        self.url = url
        self.createdDateAttribute = createdDateAttribute
        self.modifiedDateAttribute = modifiedDateAttribute
        self.fileSizeAttribute = fileSizeAttribute
    }

    convenience init?(pasteboardPropertyList propertyList: Any, ofType type: NSPasteboard.PasteboardType) {
        guard let data = propertyList as? Data,
            let tidi = try? PropertyListDecoder().decode(TidiFile.self, from: data) else { return nil }
        self.init(url: tidi.url, createdDateAttribute: tidi.createdDateAttribute, modifiedDateAttribute: tidi.modifiedDateAttribute, fileSizeAttribute: tidi.fileSizeAttribute)
    }

}

extension TidiFile : NSPasteboardWriting, NSPasteboardReading
{

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

    public func writableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] {
        return [.tidiFile]
    }

    public func pasteboardPropertyList(forType type: NSPasteboard.PasteboardType) -> Any? {
        if type == .tidiFile {
            return try? PropertyListEncoder().encode(self)
        }
        return nil
    }

    public static func readableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] {
        return [.tidiFile]
    }

    public static func readingOptions(forType type: NSPasteboard.PasteboardType, pasteboard: NSPasteboard) -> NSPasteboard.ReadingOptions {
        return .asData
    }

}