NSScrollView com layout automático não redimensionado até que a primeira janela manual seja redimensionada

Eu tenho um aplicativo OSX Cocoa que foi construído de forma programática (ou seja, não com um NIB / XIB), que estou tentando fazer layouts usando o layout automático - mas estou tendo um comportamento estranho quando a janela é exibida pela primeira vez.

Meu conteúdo principal é um NSView que possui uma coleção de 100 NSButtons como sub-visualizações, dispostas verticalmente. Os botões são todos restritos em relação ao NSView e um ao outro; o NSView e todos os NSButtons têmtranslatesAutoresizingMaskIntoConstraints=NO conjunto. Acredito que o código para a exibição do conteúdo seja bom (ou seja, sem layouts ambíguos etc.), porque se eu definir o contentView da janela principal como o NSView, os botões serão exibidos conforme o esperado.

No entanto, se eu definir o contentView da janela principal como um NSScrollView e definir o documentView do NSScrollView como o NSView, recebo problemas de exibição.

Na primeira exibição, recebo uma janela em branco - sem barras de rolagem, nada:

O NSScrollView possuitranslatesAutoresizingMaskIntoConstraints=NO. Para fins de depuração, também defini a cor de fundo do NSScrollView como azul, para que eu possa confirmar o que está sendo definido onde - mas não há azul mostrado em qualquer lugar.

Mas, assim que redimensiono a janela, o layout entra em ação e recebo um NSScrollView em tamanho real da janela principal, com fundo azul e barras de rolagem conforme o esperado:

Eu li algumas referências que sugerem que o problema é a falta de restrições no clipView que faz parte do NSScrollView. Nessa base, tentei configurar a ligação de restrições[NSScrollView contentView] para[NSScrollView documentView] nas direções vertical e horizontal (com constante 0, multiplicador 1, à esquerda, direita, superior e inferior). Quando faço isso, o NSScrollView agora está visível no primeiro monitor, mas é do tamanho errado. A rolagem não rola a altura total do conteúdo interno - o conteúdo rolável rola como se tivesse o mesmo tamanho da janela visível. Por fim, o conteúdo se sobrepõe à barra de título da janela:

Novamente, assim que redimensiono a janela, as restrições entram em ação e a janela é exibida conforme o esperado (veja a captura de tela anterior). Então, suponho que as restrições extras não machucam, mas também não parecem adicionar nada.

Assuntos ainda mais confusos - se eu deixar os botões totalmente desativados e usar apenas um NSView vazio sem subvisões como a exibição do conteúdo, recebo uma janela cheia de azul na inicialização, como seria de esperar.

Então - o que está acontecendo aqui? Parece que estou perdendo uma chamada para forçar a avaliação de restrições nos botões; é esse o caso ou algo mais está acontecendo aqui?

Para os interessados - aqui está o meu código de exemplo. Não é o Objetivo C - é Python - mas a ligação da linguagem pode converter os nomes dos métodos Python em mensagens do Objetivo C; o mapeamento para a API nativa do ObjectiveC deve ser óbvio:

app = NSApplication.sharedApplication()
app.setActivationPolicy_(NSApplicationActivationPolicyRegular)

main_window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(
    NSMakeRect(100, 100, 640, 480),
    NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask,
    NSBackingStoreBuffered,
    False)

scrollview = NSScrollView.alloc().init()
scrollview.setHasVerticalScroller_(True)
scrollview.setHasHorizontalScroller_(True)
scrollview.setAutohidesScrollers_(True)
scrollview.setBorderType_(NSNoBorder)
scrollview.setTranslatesAutoresizingMaskIntoConstraints_(False)

scrollview.backgroundColor = NSColor.blueColor()

container = NSView.alloc().init()
container.setTranslatesAutoresizingMaskIntoConstraints_(False)

buttons = [
    NSButton.alloc().init()
    for b in range(0, 100)
]

for i, button in enumerate(buttons):
    button.setBezelStyle_(NSRoundedBezelStyle)
    button.setButtonType_(NSMomentaryPushInButton)
    button.setTitle_(get_NSString('Button %s' % i))
    button.setTranslatesAutoresizingMaskIntoConstraints_(False)

    container.addSubview_(button)

    if i == 0:
        container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
            button, NSLayoutAttributeTop,
            NSLayoutRelationEqual,
            container, NSLayoutAttributeTop,
            1, 50,
        ))
    else:
        container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
            button, NSLayoutAttributeBottom,
            NSLayoutRelationEqual,
            buttons[i-1], NSLayoutAttributeBottom,
            1, 50,
        ))

    container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
        button, NSLayoutAttributeLeft,
        NSLayoutRelationEqual,
        container, NSLayoutAttributeLeft,
        1, 50,
    ))

    container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
        button, NSLayoutAttributeRight,
        NSLayoutRelationEqual,
        container, NSLayoutAttributeRight,
        1, -50,
    ))

container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
    buttons[-1], NSLayoutAttributeBottom,
    NSLayoutRelationEqual,
    container, NSLayoutAttributeBottom,
    1, -50,
))

scrollview.setDocumentView_(container)

main_window.setContentView_(scrollview)

main_window.makeKeyAndOrderFront_(None)

app.activateIgnoringOtherApps_(True)
app.run()

questionAnswers(3)

yourAnswerToTheQuestion