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
中的代码移动到viewDidLoad
和viewWillAppear
中,并删除属性观察者。不过我建议可选绑定 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
}
}
设置delegate
和dataSource
一次就够了。如果您使用故事板或 Xib,最方便的方法是在 Interface Builder 中连接两者。
我正在尝试在我的应用程序中创建一个文件浏览器,它在侧面板(带有拆分视图控制器)中打开。
来源是前面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
中的代码移动到viewDidLoad
和viewWillAppear
中,并删除属性观察者。不过我建议可选绑定 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
}
}
设置delegate
和dataSource
一次就够了。如果您使用故事板或 Xib,最方便的方法是在 Interface Builder 中连接两者。