Swift - 从另一个 class 调用 reloadData() 失败(发现 nil),但从自身 class 调用成功
Swift - Failed (found nil) calling reloadData() from another class but succeeded from self class
我显然正在设计一个拖放式投递箱,它可以通过单击或拖放文件来 select 文件,我想要selected 文件在它旁边的 table 中可见。我的设计逻辑是,每当用户 selects 来自 NSOpenPanel
的文件时,它会将 selected 文件路径传递到 CoreData
,然后数组将它们一一检索来自 CoreData
,最后,使用 reloadData()
.
更新 NSTableView
的内容
基本上,我的问题是每当我尝试从 DropboxButton
class 调用 ViewController().getDroppedFiles()
时,我总是得到 Fatal error: unexpectedly found nil while unwrapping an optional value.
我的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)
}
}
我正在使用一个按钮 (NSButton
) 作为保管箱(它有自己的 class),可以轻松单击它并且还支持拖动选项。
我的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
}
}
这是我的界面和代码逻辑:
那么,我怎样才能 reloadData()
在我的 ViewController class 中从另一个 class (DropboxButton: NSButton
) 中查看 table,所以每当用户将文件拖放到保管箱中时,table 视图将重新加载?
P.S。完成这件事对我来说意义重大,我真的需要在短时间内解决这个问题,有没有人可以花一些时间帮助我?
您需要在 ViewController
的加载实例上调用 getDroppedFiles()
。
使用 ViewController().getDroppedFiles()
您正在创建一个 ViewController
的新实例,该实例不会在任何地方显示(因此控件未初始化导致 nil 错误)。
我发现这个解决方案对我的情况很有用。
我使用观察器从其他控制器 类 传递数据和调用函数,现在我明白我正在创建一个未加载的 ViewController
的新实例。这是我的代码:
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
}
}
现在,一切正常,我什至可以添加一个 userInfo:
来在文件和 类 之间传递数据。
我显然正在设计一个拖放式投递箱,它可以通过单击或拖放文件来 select 文件,我想要selected 文件在它旁边的 table 中可见。我的设计逻辑是,每当用户 selects 来自 NSOpenPanel
的文件时,它会将 selected 文件路径传递到 CoreData
,然后数组将它们一一检索来自 CoreData
,最后,使用 reloadData()
.
NSTableView
的内容
基本上,我的问题是每当我尝试从 DropboxButton
class 调用 ViewController().getDroppedFiles()
时,我总是得到 Fatal error: unexpectedly found nil while unwrapping an optional value.
我的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)
}
}
我正在使用一个按钮 (NSButton
) 作为保管箱(它有自己的 class),可以轻松单击它并且还支持拖动选项。
我的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
}
}
这是我的界面和代码逻辑:
那么,我怎样才能 reloadData()
在我的 ViewController class 中从另一个 class (DropboxButton: NSButton
) 中查看 table,所以每当用户将文件拖放到保管箱中时,table 视图将重新加载?
P.S。完成这件事对我来说意义重大,我真的需要在短时间内解决这个问题,有没有人可以花一些时间帮助我?
您需要在 ViewController
的加载实例上调用 getDroppedFiles()
。
使用 ViewController().getDroppedFiles()
您正在创建一个 ViewController
的新实例,该实例不会在任何地方显示(因此控件未初始化导致 nil 错误)。
我发现这个解决方案对我的情况很有用。
我使用观察器从其他控制器 类 传递数据和调用函数,现在我明白我正在创建一个未加载的 ViewController
的新实例。这是我的代码:
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
}
}
现在,一切正常,我什至可以添加一个 userInfo:
来在文件和 类 之间传递数据。