• Apfeltalk ändert einen Teil seiner Allgemeinen Geschäftsbedingungen (AGB), das Löschen von Useraccounts betreffend.
    Näheres könnt Ihr hier nachlesen: AGB-Änderung
  • Viele hassen ihn, manche schwören auf ihn, wir aber möchten unbedingt sehen, welche Bilder Ihr vor Eurem geistigen Auge bzw. vor der Linse Eures iPhone oder iPad sehen könnt, wenn Ihr dieses Wort hört oder lest. Macht mit und beteiligt Euch an unserem Frühjahrsputz ---> Klick

[Swift] NSTabelview Drag and Drop

SpecialFighter

Fießers Erstling
Registriert
25.04.12
Beiträge
131
Hallo zusammen,

arbeite mit swift 3 für OSX und möchte gerne Drag & Drop zwischen zwei Tableviews in unterschiedlichen view Controllern realisieren. Aktuell habe ich schon folgendes simple Beispie, unter der Bedingung, das beide tableviews nur eine spalte haben, kein custom cell view und string werte:

SourceTableViewClass

Code:
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
    }
}


TargetTableViewClass

Code:
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
    }

}

Bis hier hin soweit alles super :)

Aber jetzt kommts - ich benötige eine Lösung für folgende Situation:

  • SourceTableView > eine Spalte > custom cell view > Werte pro Zeile: Vorname, Nachname
  • TargetTableView > drei Spalten > custom cell view > Werte pro Zeile: Vorname, Nachname, Alter

Die Werte erhalte ich via core data:
Code:
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 { }
}


So habe ich mein SourceTableView "modifiziert":
Code:
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
   }
}

aber wenn ich dann versuche die Row mit dem Eintrag "Max" zu draggen, stürzt meine App ab:

Code:
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.