2
votes

***** SOLUTION THAT WORKED FOR ME ******

Quit and restart Xcode fixed the issue


I'm using Xcode 10 and swift 4 for my project.

I'm creating my own viewControllers using IB to have them integrated if custom views in my project.

On one of these view controllers I'm using an NSOutlineView to display a list of network appliances.

    public class applianceListPickerViewController: NSViewController, NSOutlineViewDelegate, NSOutlineViewDataSource {




@IBOutlet weak var applianceTreeView: NSOutlineView!
private var listOfAppliances = [appliance]()

override public func viewDidLoad() {
    super.viewDidLoad()
    // Do view setup here.

        self.applianceTreeView.dataSource = self
        self.applianceTreeView.delegate = self
        self.readRouterListFromFile(fileName: "lab_list")
        self.applianceTreeView.reloadData()
}

func readRouterListFromFile(fileName: String) -> Any?
{
    var listOfRouters = [BSDRouters]()
    if let path = Bundle.main.path(forResource: fileName, ofType: "json") {
        do {
            let fileUrl = URL(fileURLWithPath: path)
            // Getting data from JSON file using the file URL

            let data = try Data(contentsOf: fileUrl, options: .mappedIfSafe)
            listOfRouters = try JSONDecoder().decode([BSDRouters].self, from: data)

        } catch {
            // Handle error here
            print ("Not a valid Router list \(error)")
            return nil
        }
    }
    else{
        return nil
    }
    for currentRouter in listOfRouters {
        let anAppliance = appliance.init(withName: currentRouter.name)
        self.listOfAppliances.append(anAppliance    )
    }
    return listOfRouters
}

// MARK: - Data Source functions


// This one returns the appliances count if item is an appliance and pipe counts if its a pipe

private func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
    if let currentItem = item as? appliance {
        return currentItem.listOfipes.count
    }
    return listOfAppliances.count

}


private func outlineView(_ outlineView: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any?{
    print("Don't know why I have to define this one but its in the error message so I declare it")
    return nil
}

// This one returns an appliance object if item is an appliance and a pipe object  if its a pipe

private func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
    if let currentItem = item as? appliance {
        return currentItem.listOfipes[index]
    }

    return listOfAppliances[index]
}

private func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
    if let currentItem = item as? appliance {
        return currentItem.listOfipes.count > 0
    }
    return false
}

// MARK: - Delegates functions functions


private func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
    var view: NSTableCellView?
    if let currentItem = item as? appliance {
        view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "routerCell"), owner: self) as? NSTableCellView
        if let textField = view?.textField {
            textField.stringValue = currentItem.name
            textField.sizeToFit()
        }
    }
    return view
}}

I'm getting the following error message in the debug section:

Illegal NSOutlineView data source (). Must implement outlineView:numberOfChildrenOfItem:, outlineView:isItemExpandable:, outlineView:child:ofItem: and outlineView:objectValueForTableColumn:byItem:

Which is unfortunate as I have defined the methods!

Reading at the documentation it says that optional method outlineView(_ outlineView: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? is mandatory when not using Cocoa bindings which I do as I manually set the datasource and delegate.

I've been also looking at this : Error: Illegal NSOutlineView data source but it doesn't contain any leads to resolve my issue.

On the IB I've linked the outlet applianceTreeView to the OutlineView of my xib.

I've tried to set the delegate and the datasource of the applianceTreeView manually after the viewdidload as it appears that the nsoutlineview doesn't conform to the protocols for delegate and datasource but without success still getting the same error message.

Editing :

Maybe something is wrong in the datasource and delegate assignment as I can see that the datasource and delegate are not pointing to the viewcontroler (self 0x00006000000e3300) but to the outlineview (outlineview 0x0000000101603e40) as shown in the image below : enter image description here

1
Why are you reloading data with viewDidLoad?El Tomato
bocaux eI'ml loading the content of the appliance list in viewed load. as the list is pretty much staticDavid Guillet
Are dataSource and delegate of the outline view connected in the storyboard?Willeke
Actually no as I said I'm defining them in the viewed load as I'm creating my own ViewController.David Guillet
Ok so quitting Xcode and restarting it fixed the issue !!!!David Guillet

1 Answers

2
votes

Replace private with public

// This one returns the appliances count if item is an appliance and pipe counts if its a pipe

public func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
    if let currentItem = item as? appliance {
        return currentItem.listOfipes.count
    }
    return listOfAppliances.count

}


public func outlineView(_ outlineView: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any?{
    print("Don't know why I have to define this one but its in the error message so I declare it")
    return nil
}