Nstableview drag and drop with custom cell views

I am working with swift 3 for osx and I am looking for a drag and drop solution between two NSTableViews in different view dispatchers.

I have a simple working solution for the case that in each view of the table there is only one column, there are no user views of cells and string values.

SourceTableView

import Cocoa class SourceTableView: NSViewController, NSTableViewDelegate, NSTableViewDataSource { @IBOutlet weak var leftTableView: NSTableView! var dataArray: NSMutableArray = ["Item 1","Item 2","Item 3"] let pbStringType = "NSPasteBoardStringType" let pbIndexType = "NSPasteBoardIndexType" func numberOfRows(in tableView: NSTableView) -> Int { return dataArray.count } func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { return dataArray[row] } func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool { let data = (dataArray as NSArray).objects(at:rowIndexes as IndexSet) pboard.declareTypes([pbStringType, pbIndexType], owner: nil) pboard.setData(NSKeyedArchiver.archivedData(withRootObject: data), forType: pbStringType) pboard.setData(NSKeyedArchiver.archivedData(withRootObject: rowIndexes), forType: pbIndexType) return true } } 

TargetTableView

 import Cocoa class TargetVC2: NSViewController, NSTableViewDelegate, NSTableViewDataSource { @IBOutlet weak var rightTableView: NSTableView! var dataArray: NSMutableArray = ["Item 5", "Item 6", "Item 7"] let pbStringType = "NSPasteBoardStringType" let pbIndexType = "NSPasteBoardIndexType" override func viewDidLoad() { super.viewDidLoad() rightTableView.register(forDraggedTypes: [pbStringType]) } func numberOfRows(in tableView: NSTableView) -> Int { return dataArray.count } func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { return dataArray[row] } func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool { let data = dataArray.objects(at:rowIndexes as IndexSet) pboard.declareTypes([pbStringType, pbIndexType], owner: nil) pboard.setData(NSKeyedArchiver.archivedData(withRootObject: data), forType: pbStringType) pboard.setData(NSKeyedArchiver.archivedData(withRootObject: rowIndexes), forType: pbIndexType) return true } func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation { if dropOperation == .above { return .move } return [] } func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool { var dropRow = row if info.draggingSource() as! NSTableView == rightTableView && tableView == rightTableView && dropOperation == .above { let data = info.draggingPasteboard().data(forType: pbIndexType)! let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: data) as! NSIndexSet dataArray.removeObjects(at: rowIndexes as IndexSet) dropRow -= rowIndexes.countOfIndexes(in: NSMakeRange(0, dropRow)) } let data = info.draggingPasteboard().data(forType: pbStringType)! let draggedStrings = NSKeyedUnarchiver.unarchiveObject(with: data) as! [Any] dataArray.insert(draggedStrings, at:IndexSet(integersIn:dropRow..<(dropRow + draggedStrings.count))) rightTableView.reloadData() return true } } 

But now I need a solution for the following case:

  • SourceTableView> single column> custom cell view> cell values: firstName, secondName
  • TargetTableView> three columns> custom cell view> cell values: firstName, secondName, Age

the values ​​that I get through the main data:

 func requestValues() { var values= [Person]() let appdelegate = NSApplication.shared().delegate as! AppDelegate let context = appdelegate.persistentContainer.viewContext let request = NSFetchRequest<Person>(entityName: "Person") do { values = try context.fetch(request) SourceTableView.reloadData() } catch { } } 

But my solution above does not work with my new β€œwish scenario”

UPDATE For example: I changed my SourceTabelView as follows:

 import Cocoa struct structData { var firstname:String var secondname:String } class SourceVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource { @IBOutlet weak var leftTableView: NSTableView! var people = [structData]() let pbStringType = "NSPasteBoardStringType" let pbIndexType = "NSPasteBoardIndexType" override func viewDidLoad() { people.append(structData(firstname:"Max",secondname:"Mustermann")) } func numberOfRows(in tableView: NSTableView) -> Int { return people.count } func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { return people[row].firstname } func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool { let data = (people as NSArray).objects(at:rowIndexes as IndexSet) pboard.declareTypes([pbStringType, pbIndexType], owner: nil) pboard.setData(NSKeyedArchiver.archivedData(withRootObject: data), forType: pbStringType) pboard.setData(NSKeyedArchiver.archivedData(withRootObject: rowIndexes), forType: pbIndexType) return true } } 

It works fine, but if I drag the line with the value "Max" =>, my application crashes with this error:

 2017-06-12 07:51:09.096744+0200 TableView-DragDrop[10315:1489730] -[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x6080000910d0 2017-06-12 07:51:09.100198+0200 TableView-DragDrop[10315:1489730] [General] -[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x6080000910d0 2017-06-12 07:51:09.129238+0200 TableView-DragDrop[10315:1489730] [General] ( 0 CoreFoundation 0x00007fffaf4d657b __exceptionPreprocess + 171 1 libobjc.A.dylib 0x00007fffc489a1da objc_exception_throw + 48 2 CoreFoundation 0x00007fffaf556f14 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132 3 CoreFoundation 0x00007fffaf449c93 ___forwarding___ + 1059 4 CoreFoundation 0x00007fffaf4497e8 _CF_forwarding_prep_0 + 120 5 Foundation 0x00007fffb0ed695a _encodeObject + 1241 6 Foundation 0x00007fffb0ed7f0c -[NSKeyedArchiver _encodeArrayOfObjects:forKey:] + 460 7 Foundation 0x00007fffb0ed695a _encodeObject + 1241 8 Foundation 0x00007fffb0f12492 +[NSKeyedArchiver archivedDataWithRootObject:] + 156 9 TableView-DragDrop 0x00000001000029a3 _TFC18TableView_DragDrop8SourceVC9tableViewfTCSo11NSTableView13writeRowsWithV10Foundation8IndexSet2toCSo12NSPasteboard_Sb + 915 10 TableView-DragDrop 0x0000000100002e5c _TToFC18TableView_DragDrop8SourceVC9tableViewfTCSo11NSTableView13writeRowsWithV10Foundation8IndexSet2toCSo12NSPasteboard_Sb + 108 11 AppKit 0x00007fffad6fc109 -[NSTableView _sendDataSourceWriteDragDataWithIndexes:toPasteboard:] + 102 12 AppKit 0x00007fffad6fcd06 -[NSTableView _performClassicDragOfIndexes:hitRow:event:] + 180 13 AppKit 0x00007fffad21e7b5 -[NSTableView _performDragFromMouseDown:] + 468 14 AppKit 0x00007fffad21cadf -[NSTableView mouseDown:] + 735 15 AppKit 0x00007fffad84024f -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 6341 16 AppKit 0x00007fffad83ca6c -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 1942 17 AppKit 0x00007fffad83bf0a -[NSWindow(NSEventRouting) sendEvent:] + 541 18 AppKit 0x00007fffad6c0681 -[NSApplication(NSEvent) sendEvent:] + 1145 19 AppKit 0x00007fffacf3b427 -[NSApplication run] + 1002 20 AppKit 0x00007fffacf05e0e NSApplicationMain + 1237 21 TableView-DragDrop 0x000000010000444d main + 13 22 libdyld.dylib 0x00007fffc517b235 start + 1 23 ??? 0x0000000000000003 0x0 + 3 ) 2017-06-12 07:51:09.148230+0200 TableView-DragDrop[10315:1489730] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it. 
+5
source share
1 answer

The reason for the failure is: Swift runtime cannot find encodeWithCoder for your structure type.

You may need to implement encodeWithCoder. The structData structure must match encodeWithCoder.

Please see the following links on how to do the same.

Example-1 Example-2 Example-3

+3
source

Source: https://habr.com/ru/post/1268754/


All Articles