Я работал над той же проблемой (программно создавая таблицы прокрутки). Я построил макетную версию, которая работала за исключением этой конкретной проблемы.
Когда NSTableView имеет NSTableHeaderView, NSScrollview фактически имеет ДВА NSClipview. Одна, доступная из свойства .contentView, содержит табличное представление, вторая содержит заголовок и NSVisualEffectView. Они оба являются подпредставлениями прокрутки.
Я заставил его вести себя, то есть показать верхнюю строку, настроив вставки contentView:
scrollView.contentView.contentInsets = NSEdgeInsets(top: headerView!.frame.height, left: 0, bottom: 0, right: 0)
Я пробовал различные стратегии автоматического размещения, которые не работали или казались сомнительными.
Вот пример того, как выглядит таблица с двумя столбцами, заполненная сгенерированными данными, чтобы я мог видеть, что происходит.
Обзор (не код, а единственный способ получить его для форматирования):
Scroll View Subviews: 4
NSClipView
NSTableBackgroundView (-250.0, -456.0, 1000.0, 456.0)
NSTableView (0.0, 0.0, 500.0, 4750.0)
NSClipView
NSVisualEffectView (0.0, 0.0, 500.0, 23.0)
NSTableHeaderView (0.0, 0.0, 500.0, 23.0)
NSScroller
NSScroller
Два просмотра клипов с их рамками. 0 - просмотр содержимого:
ClipView 0 (0.0, 0.0, 500.0, 438.0)
NSTableBackgroundView 0 (-250.0, -456.0, 1000.0, 456.0)
NSTableView 1 (0.0, 0.0, 500.0, 4750.0)
ClipView 1 (0.0, 0.0, 500.0, 23.0)
NSVisualEffectView 0 (0.0, 0.0, 500.0, 23.0)
NSTableHeaderView 1 (0.0, 0.0, 500.0, 23.0)
Все еще не до конца понимаю, что происходит.
Но я верю, что знание того, как это работает под капотом, без магии IB, является полезным упражнением.