【问题标题】:Swift - Failed (found nil) calling reloadData() from another class but succeeded from self classSwift - 从另一个类调用 reloadData() 失败(找到 nil),但从 self 类调用成功
【发布时间】:2019-03-18 23:46:02
【问题描述】:

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

基本上,我的问题是,每当我尝试从 DropboxButton 类调用 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) 作为 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
    }
}

这是我的界面和代码逻辑:

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

附:完成这件事对我来说意义重大,我真的需要在短时间内解决这个问题,有没有人可以花点时间帮助我?

【问题讨论】:

    标签: macos cocoa nstableview xcode10 swift4.2


    【解决方案1】:

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

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

    【讨论】:

    • 哦,我想我明白了!那么,您的意思是我应该实例化加载的 ViewController 以调用该函数吗?
    • 看你的图,我会让按钮生成一个视图控制器正在监听的事件,以便视图控制器可以调用 getDroppedFiles()
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-12
      相关资源
      最近更新 更多