Swift Drag and Drop won't work outside Xcode - xcode

I have some code, that works in a command line tool. Now i wanted to make it a Drop-Applet to get by the terminal and paths. I am dropping some files to it and as long as the Debugger is attached it works like a charm.
So far so good, but when I start it directly (from the Xcode output directory), it seems the drag/drop is not accepted. (Animation of the file back to the origin).
class dragView : NSView, NSDraggingDestination {
required init(coder: NSCoder) {
super.init(coder: coder)
}
override init(frame: NSRect) {
super.init(frame: frame)
let types = [NSFilenamesPboardType, NSURLPboardType]
registerForDraggedTypes(types)
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
NSColor.whiteColor().set()
NSRectFill(dirtyRect)
}
override func draggingEntered(sender: NSDraggingInfo!) -> NSDragOperation {
return NSDragOperation.Copy
}
override func draggingUpdated(sender: NSDraggingInfo!) -> NSDragOperation {
return NSDragOperation.Copy
}
override func performDragOperation(sender: NSDraggingInfo!) -> Bool {
let pboard: NSPasteboard = sender.draggingPasteboard()
let array : [String] = pboard.propertyListForType(String(NSFilenamesPboardType)) as [String]
for item in array
{
...
What am I missing here?

Your code doesn't work cause you must register dragged type into init(coder:) function.
This code works fine in Swift 3
import Cocoa
class DropView : NSView {
required init?(coder: NSCoder) {
super.init(coder: coder)
let types = [NSFilenamesPboardType, NSURLPboardType]
register(forDraggedTypes: types)
self.wantsLayer = true
self.layer?.backgroundColor = NSColor.white.cgColor
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
return .copy
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
guard let pasteboard = sender.draggingPasteboard().propertyList(forType: "NSFilenamesPboardType") as? NSArray,
let path = pasteboard[0] as? String
else { return false }
//GET YOUR FILE PATH !!
Swift.print("FilePath: \(path)")
return true
}
}
A more usefull example here

Related

Swift - Failed (found nil) calling reloadData() from another class but succeeded from self class

I'm apparently designing a drag and drop dropbox which can either select files by clicking it or dragging and dropping the files on it, and I want the selected files to be visible in a table next to it. My design logic is that whenever the user selects files from an NSOpenPanel, it passes the selected file paths into the CoreData and then an array retrieves them one by one from the CoreData, and finally, update the NSTableView's content by using reloadData().
Basically, my problem is that whenever I try to call ViewController().getDroppedFiles() from DropboxButton class, I always get a Fatal error: unexpectedly found nil while unwrapping an optional value.
My ViewController.swift:
import Cocoa
class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
getDroppedFiles()
}
#IBOutlet weak var DroppedFilesTableView: NSTableView!
var droppedFiles: [DroppedFiles] = [] // Core Data class definition: DroppedFiles
func numberOfRows(in tableView: NSTableView) -> Int {
return droppedFiles.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let droppedFilesCollection = droppedFiles[row]
if (tableView?.identifier)!.rawValue == "fileNameColumn" {
if let fileNameCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "fileNameCell")) as? NSTableCellView {
fileNameCell.textField?.stringValue = droppedFilesCollection.fileName!
return fileNameCell
}
} else if (tableView?.identifier)!.rawValue == "filePathColumn" {
if let filePathCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "filePathCell")) as? NSTableCellView {
filePathCell.textField?.stringValue = droppedFilesCollection.filePath!
return filePathCell
}
}
return nil
}
#IBAction func DropboxClicked(_ sender: NSButton) {
// selected file paths
for filePath in selectedFilePaths {
if let context = (NSApp.delegate as? AppDelegate)?.persistentContainer.viewContext {
let droppedFilesData = DroppedFiles(context: context)
droppedFilesData.fileName = getFileName(withPath: filePath)
droppedFilesData.filePath = filePath
do {
try context.save()
} catch {
print("Unable to save core data.")
}
}
getDroppedFiles()
}
}
func getDroppedFiles() {
if let context = (NSApp.delegate as? AppDelegate)?.persistentContainer.viewContext {
do {
try droppedFiles = context.fetch(DroppedFiles.fetchRequest())
} catch {
print("Unable to fetch core data.")
}
}
DroppedFilesTableView.reloadData() // Fatal Error: unexpectedly found nil while unwrapping an optional value (whenever I call this function in other class)
}
}
I'm using a push button (NSButton) as the dropbox (it has its own class), which can easily be clicked and also supports dragging options.
My DropboxButton.swift:
import Cocoa
class DropboxButton: NSButton {
required init?(coder: NSCoder) {
super.init(coder: coder)
registerForDraggedTypes([NSPasteboard.PasteboardType.URL, NSPasteboard.PasteboardType.fileURL])
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
// some other codes
return .copy
}
override func draggingExited(_ sender: NSDraggingInfo?) {
// some other codes
}
override func draggingEnded(_ sender: NSDraggingInfo) {
// some other codes
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
guard let pasteboard = sender.draggingPasteboard.propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? NSArray,
let filePaths = pasteboard as? [String] else {
return false
}
for filePath in filePaths {
if let context = (NSApp.delegate as? AppDelegate)?.persistentContainer.viewContext {
let droppedFilesData = DroppedFiles(context: context)
droppedFilesData.fileName = getFileName(withPath: filePath)
droppedFilesData.filePath = filePath
do {
try context.save()
} catch {
print("Unable to save core data.")
}
}
ViewController().getDroppedFiles() // found nil with reloadData() in ViewController.swift
}
return true
}
}
And this is my interface and code logic:
So, how can I reloadData() for the table view in my ViewController class from another class (DropboxButton: NSButton) so that whenever the user drags and drops files into the dropbox, the table view will reload?
P.S. To get this done means a lot to me, I really need to get this fixed in a short time, is there anyone can spend some time and help me?
You need to call getDroppedFiles() on a loaded instance of ViewController.
With ViewController().getDroppedFiles() you're creating a new instance of ViewController that is not shown anywhere (so controls are not initialized resulting in the nil error).
I found this solution useful for my case.
I used observer to pass through data and call functions from other controller classes, now I understand that I was creating a new instance of ViewController which is not loaded. Here is my code:
ViewController.swift:
class ViewController: NSViewController {
// other codes
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(getDroppedFiles), name: NSNotification.Name(rawValue: "reloadTableViewData"), object: nil)
}
#objc func getDroppedFiles() {
DroppedFilesTableView.reloadData()
}
}
DropboxButton.swift:
class DropboxButton: NSButton {
// other codes
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
// other codes
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTableViewData"), object: nil)
return true
}
}
And now, everything works perfectly, I can even add an userInfo: to pass data between files and classes.

Get file path using drag and drop (Swift macOS)?

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?
[Update to Swift 4.0 and Xcode 9]
Inspired by Implementing a drag-and-drop zone in Swift
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
This implementation allows for multiple files.
Just set the view class to DragView in Interface Builder, implement DragViewDelegate in your controller, then hook up the delegate outlet in Interface Builder. This way you get a delegate callback with the file URLs.
func dragViewDidReceive(fileURLs: [URL])
{
// Yay!
}
DragView.swift
//
// DragView.swift
//
// Copyright (c) 2020 Geri Borbás http://www.twitter.com/_eppz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import Cocoa
#objc protocol DragViewDelegate
{
func dragViewDidReceive(fileURLs: [URL])
}
class DragView: NSView
{
#IBOutlet weak var delegate: DragViewDelegate?
let fileExtensions = ["kext"]
required init?(coder: NSCoder)
{
super.init(coder: coder)
color(to: .clear)
registerForDraggedTypes([.fileURL])
}
override func draggingEntered(_ draggingInfo: NSDraggingInfo) -> NSDragOperation
{
var containsMatchingFiles = false
draggingInfo.draggingPasteboard.readObjects(forClasses: [NSURL.self], options: nil)?.forEach
{
eachObject in
if let eachURL = eachObject as? URL
{
containsMatchingFiles = containsMatchingFiles || fileExtensions.contains(eachURL.pathExtension.lowercased())
if containsMatchingFiles { print(eachURL.path) }
}
}
switch (containsMatchingFiles)
{
case true:
color(to: .secondaryLabelColor)
return .copy
case false:
color(to: .disabledControlTextColor)
return .init()
}
}
override func performDragOperation(_ draggingInfo: NSDraggingInfo) -> Bool
{
// Collect URLs.
var matchingFileURLs: [URL] = []
draggingInfo.draggingPasteboard.readObjects(forClasses: [NSURL.self], options: nil)?.forEach
{
eachObject in
if
let eachURL = eachObject as? URL,
fileExtensions.contains(eachURL.pathExtension.lowercased())
{ matchingFileURLs.append(eachURL) }
}
// Only if any,
guard matchingFileURLs.count > 0
else { return false }
// Pass to delegate.
delegate?.dragViewDidReceive(fileURLs: matchingFileURLs)
return true
}
override func draggingExited(_ sender: NSDraggingInfo?)
{ color(to: .clear) }
override func draggingEnded(_ sender: NSDraggingInfo)
{ color(to: .clear) }
}
extension DragView
{
func color(to color: NSColor)
{
self.wantsLayer = true
self.layer?.backgroundColor = color.cgColor
}
}

Drag and Drop to NSArrayController

I am struggling to pass a variable received from a drag and drop (file from finder onto NSView) to a NSArrayController in AppDelegate.
NSView receives the drag and drop:
class MyView:NSView, NSDraggingDestination {
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
}
let fileTypes = ["jpg", "jpeg", "bmp", "tif", "TIF"]
var fileTypeIsOk = false
var droppedFilePath = ""
required init?(coder: NSCoder) {
let types = [NSFilenamesPboardType, NSURLPboardType, NSPasteboardTypeTIFF]
super.init(coder: coder)
registerForDraggedTypes(types)
}
override func draggingEntered(sender: NSDraggingInfo) -> NSDragOperation {
if checkExtension(sender) == true {
fileTypeIsOk = true
return .Every
} else {
fileTypeIsOk = false
println("Dropped images rejected.")
return .None
}
}
override func performDragOperation(sender: NSDraggingInfo) -> Bool {
var go = false
if let board = sender.draggingPasteboard().propertyListForType("NSFilenamesPboardType") as? NSArray {
for indexFile in 0...board.count-1 {
println("Files dropped \(board[indexFile])")
//-> pass the variable board[indexFile] or board[] to NSArrayController
go = true
}
}
return go
}
func checkExtension(drag: NSDraggingInfo) -> Bool {
var go = false
var foundExtension = 0
var numberOfFiles = 0
if let board = drag.draggingPasteboard().propertyListForType("NSFilenamesPboardType") as? NSArray {
numberOfFiles = board.count
for indexFile in 0...numberOfFiles-1 {
if let url = NSURL(fileURLWithPath: (board[indexFile] as! String)) {
let suffix = url.pathExtension!
for ext in fileTypes {
if ext.lowercaseString == suffix {
++foundExtension
break
}
}
}
}
}
if foundExtension == numberOfFiles {
println("Dropped files have valid extension.")
go = true
} else {
println("At least one file dropped has an invalid extension.")
}
return go
}
}
in AppDelegate, I have set up an NSArrayController (pointing to data[] at the moment but I don't know how to populate data[] from board[])
func numberOfRowsInTableView(aTableView: NSTableView) -> Int {
return data.count
}
func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? {
var cellView: NSTableCellView = tableView.makeViewWithIdentifier(tableColumn!.identifier, owner: self) as! NSTableCellView
println("Reload Array")
if tableColumn!.identifier == "fileNameColumn" {
cellView.imageView!.image = NSImage(named: "GreenCircle")
cellView.textField!.stringValue = data[row]
return cellView
}
...
thank you for your help
Call the "- (void)addObjects:(NSArray *)objects;" method on your NSArrayController and pass it board:
[self.myArrayController addObjects:board];
It worked by adding in NSView: performDragOperation:
let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate
then I can reach the 'data' variable using appDelegate.data.

You need to specify a parseClassName for the PFQueryTableViewController

I created a tableViewcontroller and assigned it the custom class: PFQueryTableViewController in story board. I then also gave it the parseClassName "userMessage" and for some reason when i try to run the application I always get the same error message: NSInternalInconsistencyException', reason: 'You need to specify a parseClassName for the PFQueryTableViewController.
I dont understand why I am getting this error because I explicitly gave the class a parseClassName.
Here is my associated code for the PFQueryTabletableViewController:
import UIKit
import CoreLocation
import Parse
class TableViewController: PFQueryTableViewController, CLLocationManagerDelegate {
let userMessages = ["blah blahh blahhh", "Beep Beep Boop", "Beep Beep Bobbity boop"]
let locationManager = CLLocationManager()
var currLocation: CLLocationCoordinate2D?
override init!(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.parseClassName = "userMessage"
self.textKey = "text"
self.pullToRefreshEnabled = true
self.objectsPerPage = 40
}
private func alert(message: String){
let alert = UIAlertController(title: "Uh-OH", message: message, preferredStyle: UIAlertControllerStyle.Alert)
let action = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil)
let cancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
let settings = UIAlertAction(title: "Settings", style: UIAlertActionStyle.Default) {(action) -> Void in
UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
return
}
alert.addAction(settings)
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 120
self.tableView.rowHeight = 120
locationManager.desiredAccuracy = 100
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
alert("Cannot fetch your location!!")
}
override func queryForTable() -> PFQuery! {
let query = PFQuery(className: "Messages")
if let queryLoc = currLocation {
query.whereKey("location", nearGeoPoint: PFGeoPoint(latitude: queryLoc.latitude, longitude: queryLoc.longitude), withinMiles: 1)
query.limit = 40
query.orderByDescending("createdAt")
}else {
query.whereKey("location", nearGeoPoint: PFGeoPoint(latitude: 37.41182, longitude: -121.941125), withinMiles: 1)
query.limit = 40
query.orderByDescending("createdAt")
}
return query
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
locationManager.stopUpdatingLocation()
if(locations.count > 0) {
let location = locations[0] as CLLocation
println(location.coordinate)
currLocation = location.coordinate
} else {
alert("Cannot fetch your loation")
}
}
override func objectAtIndexPath(indexPath: NSIndexPath!) -> PFObject! {
var obj : PFObject? = nil
if(indexPath.row < self.objects.count) {
obj = self.objects[indexPath.row] as? PFObject
}
return obj
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userMessages.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath!, object: PFObject!) -> PFTableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as TableViewCell
cell.messageText.text = object.valueForKey("text") as? String
cell.messageText.numberOfLines = 0
let views = object.valueForKey("count") as Int
cell.numberOfViewsLabel.text = "\(views)"
cell.numberOfViewsLabel.text = "\((indexPath.row + 1) * 5)"
return cell
}
func addToViews(sender: AnyObject) {
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
object.incrementKey("count")
object.saveInBackgroundWithBlock { (Bool, NSError) -> Void in
//blahhh
}
self.tableView.reloadData()
}
}
`
parseClassName is a readonly variable and is only used when subclassing PFObject.
https://parse.com/docs/ios/api/Classes/PFObject.html#//api/name/parseClassName
The class name of the object.
#property (strong, readonly) NSString *parseClassName
Declared In
PFObject.h
Obj-C
#implementation MYGame
#dynamic title;
+ (NSString *)parseClassName {
return #"Game";
}
#end
Swift
class MYGame: PFObject {
class func parseClassName() -> String! {
return "Game"
}
}
In my case I had used a storyboard and needed to create an initWithCoder: method in my PFQueryTableViewController subclass. The template pointed to in the Parse.com docs lacks this method, but the first comment following the example does include an example implementation: https://gist.github.com/jamesyu/ba03c1a550f14f88f95d#gistcomment-74202
The message "You need to specify a parseClassName for the PFQueryTableViewController" is being generated because none of the methods are setting the PFQueryTableViewController's parseClassName property. You'll note that the property is defined quite plainly in the initWithStyle: method example provided in the docs. But, that method won't be called if the view is loaded via a storyboard: for that you'll need to set parseClassName in the initWithCoder: method.
Also, don't confuse subclassing a PFQueryTableViewController for a PFObject. For a PFObject you need to create a class method called parseClassName and also register the subclass before calling [Parse setApplicationId:aid clientKey:ckey]. You don't do those things for a PFQueryTableViewController or any of the other ParseUI view controllers. They rely on one or more of the init methods.

Swift: Opening a file by drag-and-drop in window

In Swift, how can I build an area in a window of my Mac app where a user can drag-and-drop a folder onto this area, and have my app receive the path of the folder?
In principle, it seems to me that this is a similar concept to Apple's CocoaDragAndDrop example app. I've tried to work my way through understanding that source code, but the app is written in Objective-C and I've not successfully managed to replicate its functionality in the app I am building.
Thank you in advance.
In a custom NSView:
override init(frame frameRect: NSRect)
{
super.init(frame: frameRect)
registerForDraggedTypes([kUTTypeFileURL,kUTTypeImage])
}
override func draggingEntered(sender: NSDraggingInfo) -> NSDragOperation
{
println("dragging entered")
return NSDragOperation.Copy
}
The catch is, to get it working I had to put that custom view as a leaf and the last view in the storyboard
This worked for me (on a NSWindow subclass):
In awakeFromNib:
registerForDraggedTypes([NSFilenamesPboardType])
Then add the following operations (at least draggingEntered and performDragOperation) to the window (or view):
func draggingEntered(sender: NSDraggingInfo) -> NSDragOperation {
let sourceDragMask = sender.draggingSourceOperationMask()
let pboard = sender.draggingPasteboard()!
if pboard.availableTypeFromArray([NSFilenamesPboardType]) == NSFilenamesPboardType {
if sourceDragMask.rawValue & NSDragOperation.Generic.rawValue != 0 {
return NSDragOperation.Generic
}
}
return NSDragOperation.None
}
func draggingUpdated(sender: NSDraggingInfo) -> NSDragOperation {
return NSDragOperation.Generic
}
func prepareForDragOperation(sender: NSDraggingInfo) -> Bool {
return true
}
func performDragOperation(sender: NSDraggingInfo) -> Bool {
// ... perform your magic
// return true/false depending on success
}
my 2 cents for OSX - swift 5 (and fixed for loading from XIBs/storybord.)
// Created by ing.conti on 31th jan 2020.
//
import Cocoa
class AnalysisView: NSView {
override init(frame frameRect: NSRect)
{
super.init(frame: frameRect)
self.registerMyTypes()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
self.registerMyTypes()
}
final private func registerMyTypes()
{
registerForDraggedTypes(
[NSPasteboard.PasteboardType.URL,
NSPasteboard.PasteboardType.fileURL,
NSPasteboard.PasteboardType.png,
NSPasteboard.PasteboardType.fileNameType(forPathExtension: "wtf")
])
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("draggingEntered")
return NSDragOperation.copy
}
override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
let allow = true // check your types...
print("prepareForDragOperation")
return allow
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
let pasteBoard = sender.draggingPasteboard
print("performDragOperation")
if let urls = pasteBoard.readObjects(forClasses: [NSURL.self]) as? [URL]{
// consume them...
print(urls)
return true
}
return false
}
}

Resources