NSOutlineView row not editable by “Return” key anymore after reloading a different table view cell

◇◆丶佛笑我妖孽 提交于 2021-02-05 08:11:32

问题


I'm running into the strangest issue with my NSOutlineView:

  • Everything is set up in a storyboard, i.e. the outline view and two NSTableCellViews
  • The two cell views are mostly the same, only one shows an icon, the other one doesn't
  • I can begin editing an item (row) by pressing the Return key, i.e. the NSTextField that is part of my NSTableCellView enters into edit mode. This is the default behavior and works fine so far.

However:

  • After editing ends and the item was changed, I use the second table view cell from the storyboard (the one without an icon).
  • Now entering "edit" mode by pressing the Return key does not work anymore! The app beeps and that's it.

Both cell views on their own are editable when they are initially loaded. I confirmed this. The problem occurs when an item is first shown with one table cell view, then with the other one (and vice versa).

Editing an item multiple times works fine then the underlying NSTableCellView does not change. Can anybody shine some light at what is going on here?

To reproduce:

  1. New Xcode project, Mac app
  2. Add an NSOutlineView to your view controller with one column
  3. Add two table view cells, "One", "Two" (identifiers)
  4. Use the code below

Steps:

  1. Run the app, select the second item
  2. Press "Return", type "green", "Return"
  3. Press "Return" again to enter edit mode a second time

Expected:

  • Cell should become editable again

Actual:

  • App beeps

Code:

import Cocoa

class ViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate, NSTextFieldDelegate {

    @IBOutlet var outlineView: NSOutlineView!

    private var items = ["One", "Two"]

    func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
        return item == nil ? items.count : 0
    }

    func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
        return items[index]
    }

    func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
        return false
    }

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

        NSLog("Vending cell view for: \(item)")

        let identifier = item.contains("green") ? "Two" : "One"

        if let view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: identifier), owner: nil) as? NSTableCellView
        {
            view.textField?.stringValue = item

            view.textField?.delegate = self

            return view
        }
        return nil
    }

    func controlTextDidEndEditing(_ obj: Notification) {
        NSLog("Did end editing")

        guard
            let textField = obj.object as? NSTextField,
            let item      = outlineView.item(atRow: outlineView.row(for: textField)) as? String else {
            return
        }

        NSLog("Reloading item: \(item)")

        let row = outlineView.row(for: textField)

        items[row] = textField.stringValue

        outlineView.reloadItem(item)
    }
}

UPDATE:

I found a workaround, but this looks like a bug to me. If I call outlineView.reloadData(forRowIndexes:columnIndexes:) right after reloadItem(), the problem does not occur.

Doesn't work (problem occurs):

outlineView.reloadItem(item)

Doesn't work (outlineView's data model not updated, shows old value):

outlineView.reloadData(forRowIndexes: IndexSet([row]), columnIndexes: IndexSet([0]))

This finally works:

outlineView.reloadItem(item)
outlineView.reloadData(forRowIndexes: IndexSet([row]), columnIndexes: IndexSet([0]))

The above causes the cell view to be requested a second time.

来源:https://stackoverflow.com/questions/60397648/nsoutlineview-row-not-editable-by-return-key-anymore-after-reloading-a-differe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!