nstableview 拖放与自定义单元格视图

Posted

技术标签:

【中文标题】nstableview 拖放与自定义单元格视图【英文标题】:nstableview drag and drop with custom cell views 【发布时间】:2017-11-13 06:10:48 【问题描述】:

我使用 swift 3 for osx,我正在寻找不同视图控制器中两个 NSTableView 之间的拖放解决方案。

我有一个简单的解决方案,每个表格视图只有一列,没有自定义单元格视图和字符串值。

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
    

目标表视图

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
    


但现在我需要针对以下情况的解决方案:

SourceTableView > 一列 > 自定义单元格视图 > 每个单元格的值:firstName、secondName TargetTableView > 三列 > 自定义单元格视图 > 每个单元格的值:firstName、secondName、Age

我通过核心数据获得的价值:

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  

但我上面的解决方案不适用于我的新“愿望场景”

更新 例如:我这样修改了我的 SourceTabelView:

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
    

它工作正常,但如果我拖动值为“Max”的行 => 我的应用程序会因以下错误而崩溃:

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.

【问题讨论】:

嘿。以下答案是否解决了问题?如果是,请接受它作为答案。 【参考方案1】:

崩溃的原因是,Swift 运行时无法为您的结构类型找到 encodeWithCoder。

您可能需要实现 encodeWithCoder。您的 structData 结构应符合 encodeWithCoder。

请查看以下链接了解如何做同样的事情

Example-1Example-2Example-3

【讨论】:

也许有帮助。但无法在我的项目中实现它:( 困难在哪里?

以上是关于nstableview 拖放与自定义单元格视图的主要内容,如果未能解决你的问题,请参考以下文章

如何与自定义 UICollectionViewCell 单元格交互

为 NSTableView 单元格绘制带有边框和背景的文本

基于视图的 NSTableView 中的自定义背景

iOS - 使 UITableView 与自定义单元格在按钮单击时可编辑

修改单元格后更新 NSTableView

IOS拖放与缩放