Para exibir um array Foundation em uma janela do Mac, valide os tipos dos elementos e, em seguida, crie uma view para cada valor. Fazer a ponte de NSArray para [String] fornece strings; exibi-las exige uma transformação separada em rótulos do AppKit.
Este passo a passo é para um desenvolvedor que está adicionando uma pequena lista ao próprio app macOS. A tarefa concreta é exibir três nomes sintéticos — Circle, Square e Triangle — em uma pilha vertical. O exemplo deixa explícitos os tipos da coleção e dos elementos, o layout e o ciclo de vida dos objetos.
O que a ponte entre coleções realmente muda?
A Apple documenta Array e NSArray como tipos correspondentes do Swift e do Foundation, assim como String e NSString são correspondentes. Ela recomenda usar tipos de valor do Swift no código Swift comum e acessar tipos de referência do Foundation quando seu comportamento for necessário. Para esta tarefa, mantenha a coleção Foundation no limite de entrada e use depois um array Swift tipado. Trabalhando com tipos do Foundation
O tipo externo de uma coleção e o tipo dos seus elementos respondem a perguntas diferentes. NSArray identifica uma coleção ordenada de objetos. [String] acrescenta um requisito específico: cada elemento precisa poder ser usado como uma string do Swift. Nenhuma das declarações descreve uma coleção de views. O inicializador da pilha da Apple exige explicitamente [NSView]. NSArray, init(views:)
| Etapa | Tipo neste exemplo | Contrato |
|---|---|---|
| Entrada do Foundation | NSArray |
Contém os objetos sintéticos fornecidos |
| Modelo validado | [String] |
Cada elemento atende ao requisito de string |
| Objetos de apresentação | [NSView] |
Cada elemento é um rótulo de texto recém-criado |
| Contêiner de layout | NSStackView |
Organiza essas views de acordo com sua configuração |
A distinção útil é entre fazer a ponte e construir. Fazer a ponte conecta representações compatíveis, como strings do Foundation e strings do Swift. Construir objetos NSTextField cria objetos de apresentação com propriedades e ciclo de vida próprios. Não há uma ponte documentada de string para rótulo; o caminho compatível é chamar o inicializador do rótulo para cada string. Array, init(labelWithString:)
Como validar os elementos sem descartar itens?
Use uma conversão condicional quando for necessário verificar o contrato dos elementos da coleção recebida. A Apple documenta que as? produz um resultado opcional e que uma conversão forçada malsucedida com as! provoca um erro em tempo de execução. Trate a falha explicitamente antes de construir a interface. Lidando com métodos e objetos de tipos dinâmicos no Swift
O código a seguir faz uma verificação completa usando apenas o Foundation e uma entrada sintética. Salve-o como BridgeCheck.swift e execute-o em um Mac com as ferramentas do Swift usando swift BridgeCheck.swift. As asserções expressam os resultados esperados.
import Foundation
let source: NSArray = [
NSString(string: "Circle"),
NSString(string: "Square"),
NSString(string: "Triangle")
]
let names = source as? [String]
assert(names == ["Circle", "Square", "Triangle"])
let mixed: NSArray = [NSString(string: "Circle"), NSNumber(value: 7)]
assert((mixed as? [String]) == nil)
let empty: NSArray = []
assert((empty as? [String]) == [])
print("Collection checks passed.")
A primeira conversão solicita um array de strings, portanto verifica o tipo de elemento exigido ao obter a coleção tipada. A entrada mista não atende a esse contrato. A entrada vazia atende: ela não contém nenhum elemento incompatível. Essas são verificações ilustrativas do contrato de entrada escolhido, não medições nem resultados de um app.
Evite substituir por compactMap { $0 as? String } apenas para fazer uma coleção mista passar. A Apple define compactMap como uma operação que retorna somente os resultados da transformação que não sejam nil. Neste exemplo, essa abordagem descartaria o número e exibiria uma lista incompleta. Filtrar pode ser adequado quando isso é solicitado explicitamente; aqui, a tarefa exige preservar todos os itens fornecidos. compactMap(_:)
Quando a validação for concluída com sucesso, use map para criar um rótulo para cada nome. A Apple documenta map como uma operação que aplica uma transformação aos elementos da sequência e NSTextField(labelWithString:) como a criação de um rótulo estático, sem quebra de linha e com texto não selecionável. Isso torna a transformação adequada para esses três nomes curtos. map(_:), init(labelWithString:)
Como construir a janela completa do Mac?
Este exemplo independente requer o macOS 14 ou posterior e as ferramentas de linha de comando do Xcode instaladas. Ele cria a interface por meio de código, portanto não precisa de storyboard, nib, recurso ou arquivo-fonte adicional. O requisito do macOS 14 contempla o uso de NSApplication.activate() no exemplo, que solicita a ativação sem garanti-la. activate()
Salve o programa completo abaixo como CollectionDemo.swift. Ele inclui deliberadamente seu próprio ponto de entrada. Ao adaptá-lo a um app existente, use o ponto de entrada e o ciclo de vida já estabelecidos pelo app, em vez de adicionar outro.
import Foundation
import AppKit
@MainActor
final class DemoDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow?
func applicationDidFinishLaunching(_ notification: Notification) {
let source: NSArray = [
NSString(string: "Circle"),
NSString(string: "Square"),
NSString(string: "Triangle")
]
guard let names = source as? [String] else {
print("Expected a collection containing only strings.")
NSApplication.shared.terminate(nil)
return
}
let labels: [NSView] = names.map { name in
NSTextField(labelWithString: name)
}
let stack = NSStackView(views: labels)
stack.orientation = .vertical
stack.alignment = .leading
stack.spacing = 8
stack.translatesAutoresizingMaskIntoConstraints = false
let content = NSView(frame: NSRect(
x: 0, y: 0, width: 360, height: 180
))
content.addSubview(stack)
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(
equalTo: content.leadingAnchor, constant: 20
),
stack.topAnchor.constraint(
equalTo: content.topAnchor, constant: 20
),
stack.trailingAnchor.constraint(
lessThanOrEqualTo: content.trailingAnchor, constant: -20
),
stack.bottomAnchor.constraint(
lessThanOrEqualTo: content.bottomAnchor, constant: -20
)
])
let window = NSWindow(
contentRect: content.frame,
styleMask: [.titled, .closable, .miniaturizable],
backing: .buffered,
defer: false
)
window.title = "Synthetic Shapes"
window.isReleasedWhenClosed = false
window.contentView = content
self.window = window
window.center()
window.makeKeyAndOrderFront(nil)
NSApplication.shared.activate()
}
func applicationShouldTerminateAfterLastWindowClosed(
_ sender: NSApplication
) -> Bool {
true
}
}
@main
@MainActor
enum CollectionDemo {
static let appDelegate = DemoDelegate()
static func main() {
let app = NSApplication.shared
app.setActivationPolicy(.regular)
app.delegate = appDelegate
app.run()
}
}
Compile e inicie o programa pelo Terminal, no diretório que contém o arquivo:
xcrun swiftc -parse-as-library CollectionDemo.swift -o CollectionDemo
./CollectionDemo
Com a entrada fornecida, o resultado esperado é uma janela intitulada Synthetic Shapes contendo os três rótulos na ordem original. Fechar a janela solicita o encerramento do app. O exemplo retorna true do método delegado que a Apple fornece para esse comportamento. applicationShouldTerminateAfterLastWindowClosed(_:)
Os exemplos foram inspecionados, mas não foram compilados nem executados aqui: o ambiente de pesquisa não oferece um compilador Swift nem o AppKit do macOS. Execute as verificações do Foundation e inspecione a janela no Mac de destino antes de integrar o exemplo.
Quais contratos de layout e ciclo de vida precisam ser preservados?
Os valores padrão documentados do inicializador da pilha são importantes: ele cria uma pilha horizontal, coloca as views fornecidas na área de gravidade inicial e desativa a tradução da máscara de redimensionamento automático para a pilha. O exemplo altera explicitamente a orientação para vertical e o alinhamento para inicial. Uma conversão de array não escolhe nenhuma dessas configurações de layout. init(views:), alignment
A pilha gerencia a disposição das views que contém. As restrições entre a pilha e a view de conteúdo que a envolve determinam onde essa disposição fica na janela. Aqui, as restrições inicial e superior definem um recuo de 20 pontos; as desigualdades final e inferior reservam espaço sem exigir que a lista curta preencha a área de conteúdo. A Apple documenta que as views de pilha usam Auto Layout e explica que desativar a tradução da máscara de redimensionamento automático permite definir as próprias restrições. NSStackView, translatesAutoresizingMaskIntoConstraints
Esta é uma demonstração de tamanho fixo com três rótulos curtos. Textos mais longos, muitas linhas ou uma interface redimensionável exigem uma decisão de layout separada — como usar quebra de linha ou rolagem — antes de ampliar o exemplo. Fazer corretamente a ponte de uma coleção maior não garante que ela caiba na apresentação.
O ciclo de vida também é separado da conversão de tipos. A Apple declara como fraca a propriedade de delegado do app. Portanto, a propriedade estática appDelegate fornece um proprietário forte explícito. O delegado também retém a janela, e a janela define isReleasedWhenClosed como false, seguindo as orientações da Apple para clientes do Swift e do ARC. delegate, isReleasedWhenClosed
A construção da interface ocorre em applicationDidFinishLaunching, que a Apple documenta como um ponto para inicialização adicional depois que o loop principal começa e antes de processar eventos. O ponto de entrada do programa chama run() para iniciar esse loop de eventos. Preserve essas responsabilidades ao mover a conversão para um app AppKit existente. applicationDidFinishLaunching(_:), run()
Os rótulos também representam um retrato estático construído. O exemplo atribui o texto de cada rótulo uma única vez. Alterar a coleção de origem depois disso exigiria código explícito para atualizar os rótulos ou reconstruir as views organizadas; a ponte e a operação de mapeamento não estabelecem uma conexão contínua.
Como localizar rapidamente um erro entre o contêiner e os elementos?
Use a sequência a seguir para identificar qual contrato falhou. Ela separa a validação de tipos das verificações de apresentação e ciclo de vida, para que um problema de layout não leve você a reescrever uma ponte que funcionou.
| Sintoma | Verificação | Próximo passo compatível |
|---|---|---|
Uma conversão para [String] retorna nil |
Cada elemento da entrada atende ao requisito de string? | Rejeite a coleção explicitamente ou defina uma política intencional de conversão. |
Um array inteiro está sendo convertido para String |
O destino precisa de um valor ou de uma coleção? | Valide [String]; escolha um elemento somente se a tarefa realmente precisar de um. |
| Um inicializador de pilha rejeita o argumento | O argumento é [String], em vez de [NSView]? |
Primeiro, mapeie cada string para um rótulo. |
| Os rótulos aparecem na horizontal | A orientação da pilha foi configurada? | Defina .vertical para esta lista. |
| As views estão mal posicionadas ou há conflito entre restrições | As restrições da view que envolve a pilha e as configurações da máscara de redimensionamento automático são consistentes? | Inspecione o layout independentemente da conversão de entrada. |
| As chamadas de retorno do delegado não chegam | Um proprietário forte mantém o delegado retido? | Mantenha o delegado vivo além da atribuição à propriedade fraca. |
| Alterações posteriores no modelo não aparecem | Há código explícito de atualização? | Atualize deliberadamente os valores dos rótulos ou as views organizadas. |
Para esta tarefa, o caminho confiável é validar a entrada do Foundation uma vez, manter o modelo tipado resultante, construir um rótulo para cada valor e configurar explicitamente a pilha e o ciclo de vida do app. Cada etapa tem um contrato visível, o que facilita diagnosticar falhas à medida que a interface do Mac cresce.
Fontes
NSArray — Apple
Array — Apple
Lidando com métodos e objetos de tipos dinâmicos no Swift — Apple
compactMap(_:) — Apple
map(_:) — Apple
init(labelWithString:) — Apple
NSStackView — Apple
init(views:) — Apple
alignment — Apple
delegate — Apple
isReleasedWhenClosed — Apple
run() — Apple
activate() — Apple