Swift - 失败(找到nil)从另一个类调用reloadData()但是从self类成功

问题描述 投票:0回答:2

我显然正在设计一个拖放式dropbox,它可以通过单击或拖放文件来选择文件,我希望所选文件在旁边的表格中可见。我的设计逻辑是,每当用户从NSOpenPanel中选择文件时,它会将选定的文件路径传递到CoreData,然后一个数组从CoreData逐个检索它们,最后,使用NSTableView更新reloadData()的内容。

基本上,我的问题是每当我尝试从ViewController().getDroppedFiles()类调用DropboxButton时,我总是得到一个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)作为dropbox(它有自己的类),可以轻松点击并支持拖动选项。

我的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
    }
}

这是我的界面和代码逻辑:user interface and code logic

那么,我如何从另一个类(reloadData())中查看我的ViewController类中的表视图DropboxButton: NSButton,以便每当用户将文件拖放到dropbox中时,表视图将重新加载?

附:要做到这一点对我来说意义重大,我真的需要在短时间内解决这个问题,是否有人可以花一些时间来帮助我?

macos cocoa nstableview xcode10 swift4.2
2个回答
0
投票

你需要在加载的getDroppedFiles()实例上调用ViewController

使用ViewController().getDroppedFiles(),您将创建一个未在任何位置显示的ViewController的新实例(因此控件未初始化,从而导致nil错误)。


0
投票

我发现这个解决方案对我的情况有用。

我使用observer从其他控制器类传递数据和调用函数,现在我明白我正在创建一个未加载的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:来传递文件和类之间的数据。

© www.soinside.com 2019 - 2024. All rights reserved.