NSTableView.setNeedsDisplay()仅在附加的Formatter更改时不重绘

问题描述 投票:0回答:1

我正在使用基于视图的NSTableView,其中一列显示日期,表格单元格视图使用共享的DateFormatter。

let view: NSTableCellView? = tableView.makeView(withIdentifier: column.identifier, owner: self) as! NSTableCellView?
let entry = (logController.arrangedObjects as! [LogEntry])[row]
    switch column.identifier {
    case columnDateKey:
        view?.textField?.formatter = sharedDateFormatter
        view?.textField?.objectValue = entry.date

应用程序具有用户首选项以选择日期格式和先前的代码

tableView.setNeedsDisplay(tableView.rect(ofColumn: tableView.column(withIdentifier: columnDateKey)))

将使用新的日期格式刷新列。

使用macOS Mojave,这不会发生。调查显示,虽然drawRect:被调用为底层TableView,但没有调用tableView(:viewFor:row :)来获取表格单元格视图的新值。调用tableView.reloadData(forRowIndexes:columnIndexes :)会导致调用tableView(:viewFor:row :),但显示不刷新(尽管它对tableView.reloadData()有效)。

重绘的任何外部原因,例如选择一行正确地单独更新该区域。我看到的另一件事是,使用长桌慢慢向上滚动最终会导致出现新格式,尽管现有单元格在返回之前滚动回过去很长时间后不会改变。这似乎可以推断,当只有附加格式化程序的配置发生更改时,存在不被视为已更改的缓存视图(尽管内容的值发生更改时)

随着Mojave的引入,这种行为发生了变化,我发现很难相信没有其他人报告它,所以我开始质疑我的原始代码。我错过了什么吗?

以下测试代码演示了此问题,不会为setNeedsDisplay的变体打印“查看请求”消息,并且仅为reloadData()重新绘制显示

styleButton是用于切换数字格式的复选框,而refreshButton是用于请求重绘的操作按钮

将值设置为随机值将导致预期的重绘行为

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!
    @IBOutlet weak var table: NSTableView!
    @IBOutlet weak var styleButton: NSButton!
    @IBOutlet weak var refreshButton: NSButton!
    @IBOutlet weak var testView: NSView!

    let numberFormatter = NumberFormatter()

    func applicationWillFinishLaunching(_ notification: Notification) {
    numberFormatter.numberStyle = symbolButton.state == NSControl.StateValue.on ? NumberFormatter.Style.decimal : NumberFormatter.Style.none
    }

    @IBAction func refresh(sender: Any?) {
        numberFormatter.numberStyle = styleButton.state == NSControl.StateValue.on ? NumberFormatter.Style.decimal : NumberFormatter.Style.none
        table.setNeedsDisplay(table.rect(ofColumn: 0))
        // table.needsDisplay = true
        // table.reloadData(forRowIndexes: IndexSet(integersIn: 0..<table.numberOfRows), columnIndexes:[0])
        // table.reloadData()
    }
}

extension AppDelegate: NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
        if tableView == table {
            return 40
        }
        return 0
    }
}

extension AppDelegate: NSTableViewDelegate {
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        print("View requested")
        guard tableColumn != nil else {
            return nil
        }
        let column = tableColumn!
        if tableView == table {
            let view: NSTableCellView? = tableView.makeView(withIdentifier: column.identifier, owner: self) as! NSTableCellView?
            view?.textField?.formatter = numberFormatter
            view?.textField?.objectValue = 123.456
            return view
        }
        return nil
    }
}
swift nstableview macos-mojave
1个回答
0
投票

错误地依赖view.setNeedsDisplay来自动更新子视图。情况并非如此(虽然之前似乎已经开始工作了) - 请参阅Willeke上面的评论

© www.soinside.com 2019 - 2024. All rights reserved.