NSOutlineView 意外发现 nil

NSOutlineView unexpectedly found nil

我正在尝试在我的应用程序中创建一个文件浏览器,它在侧面板(带有拆分视图控制器)中打开。

来源是前面viewController中的一个prepareForSegue方法带来的一个URL。

每次 vc 加载我都会出现致命错误:

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

编译器将错误定位到我声明的位置:

outlineView.delegate = self outlineView.dataSource = self

我试过了: 1. 撤销和重做我所有的网点连接,通过代码,通过 故事板 2. 通过代码、故事板重新连接委托和数据源 3. 我认为我的数据源方法可能有问题,我重写了 5 次 4.我也试过把我的setDelegatesAndDatasource方法放在viewDidAppear里面,以为是view生命周期的问题

我不明白这是怎么回事。 感谢您的帮助。

'''

extension ViewControllerSource : NSOutlineViewDataSource, NSOutlineViewDelegate {   

    func setDelegatesAndDatasources(){
        outlineView.delegate = self
        outlineView.dataSource = self
    }


    // MARK: - NSOutlineView Datasource

    func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
        if let fileSystemItem = item as? FileSystemItem {
            return fileSystemItem.children.count
        }
        return 1

    }

    func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
        if let fileSystemItem = item as? FileSystemItem {
            return fileSystemItem.children[index]
        }
        return rootfileSystemItem
    }

    func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
        if let fileSystemItem = item as? FileSystemItem {
            return fileSystemItem.hasChildren()
        }
        return false
    }

    // MARK: - NSOutlineView Delegate

    func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
        guard let colIdentifier = tableColumn?.identifier else { return nil }

        if colIdentifier == NSUserInterfaceItemIdentifier(rawValue: "col1") {
            let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "cell1")
            guard let cell = outlineView.makeView(withIdentifier: cellIdentifier, owner: nil) as? NSTableCellView else { return nil }

            if let collection = item as? FileSystemItem {
                cell.textField?.stringValue = collection.name ?? "Title not available"
                cell.textField?.isEditable = false
                cell.textField?.wantsLayer = true
                cell.imageView?.image = collection.icon
                // cell.textField?.delegate = self
            } else {
                cell.textField?.stringValue = "unknown item"
                cell.textField?.isEditable = false
                cell.textField?.wantsLayer = true
            }

            return cell
        } else {
            return nil
        }
    }


}

'''

这是主要的 viewController 文件:

'''

class ViewControllerSource: NSViewController {

    @IBOutlet var outlineView: NSOutlineView!

    var echo:Echo? {
        didSet {
            echo!.checkFolderIntegrity()
            rootfileSystemItem = FileSystemItem(url: echo!.url)
            let window = self.view.window?.windowController as! WindowControllerEcho
            window.directoryPath.url = echo!.url
        }
    }


    let propertyKeys: [URLResourceKey] = [.localizedNameKey, .effectiveIconKey, .isDirectoryKey, .typeIdentifierKey]
    var rootfileSystemItem: FileSystemItem! {
        didSet {
            displayItems()
            outlineView.reloadData()
        }
    }


    // MARK: - Initialization

    override func viewDidLoad() {
        super.viewDidLoad()
        setDelegatesAndDatasources()
    }


    func displayItems(){
        for fileSystemItem in rootfileSystemItem.children as [FileSystemItem] {
            print("item : \(fileSystemItem)")
            for subItem in fileSystemItem.children as [FileSystemItem] {
                print("\(fileSystemItem.name) - \(subItem.name)")
            }
        }
    }
}




extension ViewControllerSource : EchoDelegate {
    func didLoad(echo: Echo) {
        self.echo = echo

    }
}

'''

prepareForSegue代码揭示错误:

您正在 prepareForSegue 中设置 echo。这导致调用 属性 观察者 didSet。但是此时视图尚未加载,强制展开类型会崩溃。

解决方法是将didSet中的代码移动到viewDidLoadviewWillAppear中,并删除属性观察者。不过我建议可选绑定 window

var echo : Echo!

override func viewDidLoad() {
    super.viewDidLoad()
    setDelegatesAndDatasources()
    echo.checkFolderIntegrity()
    rootfileSystemItem = FileSystemItem(url: echo.url)
}

override func viewWillAppear(_ animated : Bool) {
    super.viewWillAppear(animated)
    if let window = self.view.window?.windowController as? WindowControllerEcho {
        window.directoryPath.url = echo.url
    }
}

设置delegatedataSource一次就够了。如果您使用故事板或 Xib,最方便的方法是在 Interface Builder 中连接两者。