swiftnstableviewappkit

NSTableView hangs when scrolled down in fullscreen mode


I've got a programmatically created/populated (view-based) NSTableView with 37 columns and around 119500 rows. This performs well enough - I can make the window as big as I like and still scroll around smoothly. However, when I've scrolled down (say halfway) and go into fullscreen mode, my app hangs (seemingly forever). Memory usage keeps climbing, I've seen it get upwards of 80GB. I can go into fullscreen mode when I'm scrolled all the way to the top, however once I'm in fullscreen mode the further I scroll down, the more lag I experience until my app beachballs.

I'm not particularly familiar with Instruments but I did a Time Profiler:

enter image description here

Where 'Weight' drops from 82.5% to 46.8% and follow the other path (with weight 35.7%, not in picture) is where I find another [NSView _commonAwake] and then [NSNotificationCenter addObserverForName: object:queue:usingBlock:].

Not sure it's important, but I haven't subclassed the NSTableCellView, though their contents (standard NSTextField) are editable. I haven't noticed a difference in behaviour when toggling editable 'off'.

What is going on here? And why does my table work fine when not in fullscreen mode (but close to the same dimensions), but does not work when either transitioning to, or in fullscreen mode? Why would fullscreen work when scrolled all the way to the top, but the further I go down, the slower it becomes until it hangs, which it doesn't do when not fullscreen?

Edit 1: In case it helps, my tableView(_:viewFor:row:) function is as follows:

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
    
    let identifier = tableColumn!.identifier
    let viewIdentifier: NSUserInterfaceItemIdentifier =
    (identifier == .indexTableColumnItem) ? .indexTableColumnItem : .stringTableColumnItem
    
    guard let cellView = tableView.makeView(withIdentifier: viewIdentifier, owner: self) as? NSTableCellView
    else {
        return nil
    }
    
    // force unwrap so they don't silently fail
    let textField = cellView.textField!
    textField.target = self
    
    if identifier == .indexTableColumnItem {
        textField.font = .monospacedSystemFont(ofSize: 12, weight: .regular)
        textField.textColor = .secondaryLabelColor
        textField.stringValue = String(row + 1)
    }
    else {
        let column: Int = tableView.column(withIdentifier: identifier)
        
        textField.stringValue = self.model[column: column - 1, row: row] ?? ""
        textField.isEditable = true
        textField.action = #selector(self.onTyping(_:))
    }
    
    return cellView
}

I have tried changing the contents of this to simply return nil, however that didn't improve the responsiveness when fullscreen.


Solution

  • Ended up setting 'Full Size Content View' in my Window (through storyboard)