UIKit SDK Patterns
Coordinator, programmatic UI, acessibilidade
SDKs que apresentam UI precisam gerenciar navegacao sem depender do navigation stack do app host. O pattern Coordinator encapsula o fluxo inteiro, enquanto programmatic Auto Layout garante controle total sem storyboards.
Por que Coordinator em SDKs?
Um SDK de verificacao de identidade tem um fluxo multi-step (permissao de camera, captura de documento, selfie, upload, resultado). O Coordinator pattern encapsula toda essa navegacao, isolando o SDK do app host.
Vantagens do Coordinator
- Isolamento: SDK controla seu proprio navigation stack
- Reutilizacao: ViewControllers nao sabem sobre navegacao
- Testabilidade: fluxo pode ser testado sem UI
- Flexibilidade: steps podem ser adicionados/removidos via config
- Cleanup: coordinator garante dismiss correto de tudo
Sem Coordinator (problemas)
- ViewControllers acoplados entre si
- SDK depende do UINavigationController do app
- Dificil pular ou reordenar steps
- Memory leaks por referencia circular entre VCs
- Testes requerem instanciar toda a hierarquia de UI
Programmatic Auto Layout
Em SDKs, preferimos Auto Layout programatico sobre storyboards/XIBs. Isso elimina conflitos de merge, permite versionamento limpo e da controle total sobre constraints.
| Aspecto | Programmatic | Storyboard/XIB |
|---|---|---|
| Versionamento | Diff legivel em PR | XML opaco, conflitos frequentes |
| Distribuicao SDK | Apenas codigo Swift | Precisa incluir resource bundles |
| Dynamic Type | Facil de adaptar constraints | Suporta mas menos flexivel |
| Performance | Sem desserializacao de XIB | Carrega e parseia XML |
| Reutilizacao | Funcoes e extensoes de layout | Dificil parametrizar |
// Auto Layout helpers para codigo limpo
extension UIView {
func pin(
to parent: UIView,
insets: UIEdgeInsets = .zero
) {
translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
topAnchor.constraint(
equalTo: parent.topAnchor,
constant: insets.top
),
leadingAnchor.constraint(
equalTo: parent.leadingAnchor,
constant: insets.left
),
trailingAnchor.constraint(
equalTo: parent.trailingAnchor,
constant: -insets.right
),
bottomAnchor.constraint(
equalTo: parent.bottomAnchor,
constant: -insets.bottom
),
])
}
func centerIn(_ parent: UIView) {
translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
centerXAnchor.constraint(equalTo: parent.centerXAnchor),
centerYAnchor.constraint(equalTo: parent.centerYAnchor),
])
}
func size(width: CGFloat? = nil, height: CGFloat? = nil) {
translatesAutoresizingMaskIntoConstraints = false
if let w = width {
widthAnchor.constraint(equalToConstant: w).isActive = true
}
if let h = height {
heightAnchor.constraint(equalToConstant: h).isActive = true
}
}
}