Tevfik Xung Tevfik Xung - 1 month ago 26
Swift Question

os x Swift: get file path using drag and drop

how to implement a drag-and-drop zone in swift 2.0?

I built an app that processes kext files but, for now, i have to manually enter the path to the input kext.
my question is: how to get file path by performing a drag and drop on a zone?

Answer Source

[Update to Swift 4.0 and Xcode 9]

Add a NSView to your main view and subclass. This code works perfect in Swift 4.0 and macOS 10.13 High Sierra!

import Cocoa

class DropView: NSView {

    var filePath: String?
    let expectedExt = ["kext"]  //file extensions allowed for Drag&Drop (example: "jpg","png","docx", etc..)

    required init?(coder: NSCoder) {
        super.init(coder: coder)

        self.wantsLayer = true
        self.layer?.backgroundColor = NSColor.gray.cgColor

        registerForDraggedTypes([NSPasteboard.PasteboardType.URL, NSPasteboard.PasteboardType.fileURL])
    }

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
        // Drawing code here.
    }

    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        if checkExtension(sender) == true {
            self.layer?.backgroundColor = NSColor.blue.cgColor
            return .copy
        } else {
            return NSDragOperation()
        }
    }

    fileprivate func checkExtension(_ drag: NSDraggingInfo) -> Bool {
        guard let board = drag.draggingPasteboard().propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? NSArray,
              let path = board[0] as? String
        else { return false }

        let suffix = URL(fileURLWithPath: path).pathExtension
        for ext in self.expectedExt {
            if ext.lowercased() == suffix {
                return true
            }
        }
        return false
    }

    override func draggingExited(_ sender: NSDraggingInfo?) {
        self.layer?.backgroundColor = NSColor.gray.cgColor
    }

    override func draggingEnded(_ sender: NSDraggingInfo) {
        self.layer?.backgroundColor = NSColor.gray.cgColor
    }

    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
        guard let pasteboard = sender.draggingPasteboard().propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? NSArray,
              let path = pasteboard[0] as? String
        else { return false }

        //GET YOUR FILE PATH !!!
        self.filePath = path
        Swift.print("FilePath: \(path)")

        return true
    }
}

To use this code you have to set "macOS Deployment Target" to 10.13

screenshot