首先我必须指出,这是我在 Swift 中的第一个 GUI 应用程序 (XIB),换句话说,我正在努力学习 Swift 和 MacOS 软件开发。我查看了 Stack 上的几个问题,以及关于 NSTableView 的 Apple 文档,但我被卡住了。
尝试制作一个简单的应用程序来读取所选文件的某些属性。我有一个自定义 NSView
用户拖放文件并从中读取一些属性 - 没问题。
>>> print("\(fileDataToShow)\n\(resultTable)")
Optional([["filename": "foo.jpeg", "state": "1"],["filename": "bar.jpeg", "state": "1"]])
Optional(<NSTableView: 0x101203070>)
@IBOutlet weak var resultTable: NSTableView!
,在包含类/NSView 的文件顶部,表明它已连接,MainMenu.XIB—ResultTable
.
我想出了以下代码,试图从我的自定义 class View: NSView {
中显示 NSTableView 中的数据。
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
<...>
func numberOfRowsInTableView(in tableView: NSTableView) -> Int {
return fileDataToShow?.count ?? 0
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{
var result:NSTableCellView
result = tableView.makeView(withIdentifier: (tableColumn?.identifier)!, owner: self) as! NSTableCellView
result.textField?.stringValue = fileDataToShow?[row][(tableColumn?.identifier.rawValue)!]! as! String
return result
}
resultTable?.beginUpdates()
// print(type(of:fileDataToShow)) // Optional<Array<Dictionary<String, Any>>>
resultTable.insertRows(at: IndexSet(integer: fileDataToShow?.count ?? 0), withAnimation: .effectFade)
resultTable.reloadData()
resultTable?.endUpdates()
}
fileDataToShow
的内容没问题,但是其他代码行,.beginUpdates()
/.insertRows(..
等似乎没有任何 Action 。
如前所述,我无法弄清楚,也不知道在哪里或如何弄清楚...有人给我一些提示和/或指示吗?
我已经在 fileDataToShow
中定义了所有的键对应于 Identifiers
在我的 XIB 中。
希望我已经成功地解释了我的问题。
编辑:
当我运行我的应用程序时,调试区域给出以下输出:
*** Illegal NSTableView data source (<NSObject: 0x600000000b90>). Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
EDIT2/更新:
谢谢@vadian,但我还是没能解决这个问题,这里有一些更新。
这是我的整个文件,DropZone.swift
:
```
class DropView: NSView/*, NSTableViewDataSource, NSTableViewDelegate*/ {
@IBOutlet weak var resultTable: NSTableView!
let dropZoneEnteredBackgroundColor = CGColor(red: 165/255, green: 165/255, blue: 165/255, alpha: 1.0)
let dropZoneExitedBackgroundColor = CGColor(red: 200/255, green: 200/255, blue: 200/255, alpha: 1.0)//NSColor.gray.cgColor
required init?(coder: NSCoder) {
super.init(coder: coder)
self.wantsLayer = true
self.layer?.backgroundColor = dropZoneExitedBackgroundColor
registerForDraggedTypes([NSPasteboard.PasteboardType.URL,
NSPasteboard.PasteboardType.fileURL])
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
self.layer?.backgroundColor = dropZoneEnteredBackgroundColor
return .copy
}
override func draggingEnded(_ sender: NSDraggingInfo) {
self.layer?.backgroundColor = dropZoneExitedBackgroundColor
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
guard let pasteboard = sender.draggingPasteboard.propertyList(forType:
NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as?
NSArray else {return false}
var droppedItems: [String: String] = [:]
for path in pasteboard {
guard let fullPath = path as? String else { return false }
let fileManager = FileManager.default
var isDir: ObjCBool = false
if fileManager.fileExists(atPath: fullPath, isDirectory:&isDir) {
if isDir.boolValue {
// the dropped item exists and it's a directory
droppedItems[path as! String] = "folder"
}
else {
// file exists and it's not a directory, hence a normal file
droppedItems[path as! String] = "file"
}
}
}
do {
var fileDataToShow = [[String:Any]]()
for object in droppedItems {
if object.value == "file" {
do {
//let fullPath = object.key
let attributes = try object.key.extendedAttributes() // Array<String>
let filename = object.key.fileName() + "." + object.key.fileExtension()
fileDataToShow.append(["state": "1",
"filename": filename,
"metadata":removed_attributes
])
}
catch {
debugPrint("Error info: \(error)")
}
}
else if object.value == "folder" {
// TODO
}
}
func numberOfRows(in tableView: NSTableView) -> Int {
return fileDataToShow.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{
let cell = tableView.makeView(withIdentifier: tableColumn?.identifier ?? NSUserInterfaceItemIdentifier(rawValue: ""), owner: self) as! NSTableCellView
// This line could crash if there values which are not String
cell.textField?.stringValue = fileDataToShow[row][tableColumn?.identifier.rawValue ?? ""] as! String
return cell
}
let insertionIndex = fileDataToShow.count
//debugPrint(resultTable) // Optional(<NSTableView: 0x10100ba10>)
//debugPrint(fileDataToShow) // [["filename": "img1.jpeg", "metadata": ["com.apple.metadata..", "com.a..."], "state": "1"]]
resultTable.insertRows(at: IndexSet(integer: insertionIndex), withAnimation: .effectGap)
} // do
return true
}
}
现在出现以下错误:
*** Canceling drag because exception 'NSTableViewException' (reason 'NSTableView error inserting/removing/moving row 2 (numberOfRows: 0).') was raised during a dragging session
抱歉,自@vadian 上次回复以来我遇到了麻烦,所以不得不再次询问。 我做错了什么?
编辑 3:
感谢您的回答,@vadian,但我不明白。我有地方 numberOfRows
和 tableView
init 函数下面的函数。并在 do block 的最后执行以下代码,以尝试更新表:
resultTable.beginUpdates()
var i = 0
for row in fileDataToShow {
print("state:",row["state"]!) // 1
print("filename:",row["filename"]!) // file.jpg
print("metadata:",row["metadata"]!) // ["com.apple.metadata..", "com.a..."]
resultTable.insertRows(at: IndexSet(integer: i), withAnimation: .effectFade)
i += 1
}
resultTable.endUpdates()
表中添加了新行,但它们都是空的。我如何 - 以任何方式 - 绑定(bind) fileDataToShow
反对resultTable.insertRows
.
如果你理解我糟糕的拼写和挑剔的问题 :) Swift 很难但学起来很有趣!
最佳答案
代码中有很多问题。
numberOfRowsInTableView
在 Swift 3+ 中是numberOfRows(in tableView:
。- 数据源/委托(delegate)方法必须在类中的顶层,而不是在
performDragOperation
中。 - 您使用了太多问号。
不要将数据源数组声明为可选,声明为空非可选数组。
var fileDataToShow = [[String:Any]]()
func numberOfRows(in tableView: NSTableView) -> Int {
return fileDataToShow.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{
let cell = tableView.makeView(withIdentifier: tableColumn.identifier!, owner: self) as! NSTableCellView
// This line could crash if there values which are not String
cell.textField?.stringValue = fileDataToShow[row][tableColumn.identifier!.rawValue)] as! String
cell result
}
要插入带有动画的行,请不要调用 reloadData()
。获取数组的最后一个索引,将项目附加到数组并插入行。
Begin-/endUpdates
没用
let insertionIndex = fileDataToShow.count
fileDataToShow.append([:]) // append some suitable dictionary
resultTable.insertRows(at: IndexSet(integer: insertionIndex), withAnimation: .effectGap)
关于swift - 如何正确地向 NSTableView 添加一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53251780/