Como Integrar Validação de CPF em um App iOS com SwiftUI

Aprenda a integrar validação de CPF em um app iOS usando SwiftUI com a API do CPFHub.io. Guia completo com MVVM, formulários e feedback visual.

Redação CPFHub.io
Redação CPFHub.io
··8 min de leitura
Como Integrar Validação de CPF em um App iOS com SwiftUI

Para integrar validação de CPF em um app iOS com SwiftUI, use o padrão MVVM: o CPFViewModel gerencia o estado e faz a chamada GET a https://api.cpfhub.io/cpf/{CPF} com async/await e o header x-api-key, enquanto a CPFFormView exibe o formulário declarativo e reage automaticamente às mudanças de estado. O resultado é uma experiência de validação em tempo real com feedback visual imediato.

Introdução

SwiftUI transformou o desenvolvimento iOS com sua abordagem declarativa para construção de interfaces. Integrar a validação de CPF em um app SwiftUI significa combinar a reatividade do framework com chamadas assíncronas à API do CPFHub.io, tudo seguindo o padrão MVVM (Model-View-ViewModel).

Arquitetura MVVM para consulta de CPF

O padrão MVVM separa a lógica de negócio da interface, facilitando testes e manutenção. O ViewModel será a ponte entre a API e a View.

import Foundation
import SwiftUI

@MainActor
class CPFViewModel: ObservableObject {
    @Published var cpfInput: String = ""
    @Published var resultado: CPFData?
    @Published var erro: String?
    @Published var isLoading: Bool = false

    var cpfFormatado: String {
    let numeros = cpfInput.filter { $0.isNumber }
    var resultado = ""
    for (index, char) in numeros.prefix(11).enumerated() {
    if index == 3 || index == 6 { resultado.append(".") }
    if index == 9 { resultado.append("-") }
    resultado.append(char)
    }
    return resultado
    }

    private let service = CPFService(
    apiKey: Bundle.main.object(
    forInfoDictionaryKey: "CPFHUB_API_KEY"
    ) as? String ?? ""
    )

    func consultar() async {
    let numeros = cpfInput.filter { $0.isNumber }
    guard numeros.count == 11 else {
    erro = "CPF deve conter 11 dígitos"
    return
    }

    isLoading = true
    erro = nil
    resultado = nil

    do {
    resultado = try await service.consultarCPF(numeros)
    } catch let error as CPFError {
    erro = error.localizedDescription
    } catch {
    erro = "Erro inesperado. Tente novamente."
    }

    isLoading = false
    }
}
ComponenteResponsabilidadePropriedade
ModelDados e regras de negócioCPFData, CPFResponse
ViewModelEstado e lógica de apresentaçãoCPFViewModel
ViewInterface declarativaCPFFormView
  • @MainActor -- garante que todas as atualizações de UI aconteçam na thread principal
  • @Published -- propriedades observáveis que atualizam a View automaticamente quando mudam
  • Bundle.main -- forma segura de armazenar a API key no Info.plist sem hardcode no código

Construindo o formulário de consulta

A View em SwiftUI é declarativa e reage automaticamente às mudanças do ViewModel.

import SwiftUI

struct CPFFormView: View {
    @StateObject private var viewModel = CPFViewModel()

    var body: some View {
    NavigationStack {
    Form {
    Section("Digite o CPF") {
    TextField("000.000.000-00", text: $viewModel.cpfInput)
    .keyboardType(.numberPad)
    .onChange(of: viewModel.cpfInput) { _, newValue in
    viewModel.cpfInput = String(
    newValue.filter { $0.isNumber }.prefix(11)
    )
    }

    Text(viewModel.cpfFormatado)
    .foregroundStyle(.secondary)
    .font(.caption)
    }

    Section {
    Button(action: {
    Task { await viewModel.consultar() }
    }) {
    HStack {
    if viewModel.isLoading {
    ProgressView()
    .padding(.trailing, 8)
    }
    Text(viewModel.isLoading ? "Consultando..." : "Validar CPF")
    }
    .frame(maxWidth: .infinity)
    }
    .disabled(viewModel.isLoading || viewModel.cpfInput.count < 11)
    }

    if let erro = viewModel.erro {
    Section {
    Text(erro)
    .foregroundStyle(.red)
    }
    }

    if let dados = viewModel.resultado {
    CPFResultadoView(dados: dados)
    }
    }
    .navigationTitle("Consulta de CPF")
    }
    }
}
  • @StateObject -- cria e gerencia o ciclo de vida do ViewModel dentro da View
  • $viewModel.cpfInput -- binding bidirecional que conecta o TextField ao estado do ViewModel
  • Task -- cria uma tarefa assíncrona para chamar a função async do ViewModel

Exibindo os resultados com componentes reutilizáveis

Separe a exibição dos resultados em um componente próprio para manter o código organizado.

import SwiftUI

struct CPFResultadoView: View {
    let dados: CPFData

    var body: some View {
    Section("Resultado da Consulta") {
    LabeledContent("Nome", value: dados.name)
    LabeledContent("CPF", value: formatarCPFExibicao(dados.cpf))
    LabeledContent("Nascimento", value: dados.birthDate)
    LabeledContent("Sexo", value: dados.gender == "M" ? "Masculino" : "Feminino")
    }
    }

    private func formatarCPFExibicao(_ cpf: String) -> String {
    let n = cpf.filter { $0.isNumber }
    guard n.count == 11 else { return cpf }
    let i = n.startIndex
    let p1 = n[i..<n.index(i, offsetBy: 3)]
    let p2 = n[n.index(i, offsetBy: 3)..<n.index(i, offsetBy: 6)]
    let p3 = n[n.index(i, offsetBy: 6)..<n.index(i, offsetBy: 9)]
    let p4 = n[n.index(i, offsetBy: 9)..<n.index(i, offsetBy: 11)]
    return "\(p1).\(p2).\(p3)-\(p4)"
    }
}

struct CPFResultadoView_Previews: PreviewProvider {
    static var previews: some View {
    Form {
    CPFResultadoView(dados: CPFData(
    cpf: "12345678909",
    name: "João da Silva",
    nameUpper: "JOÃO DA SILVA",
    gender: "M",
    birthDate: "01/01/1990",
    day: "01",
    month: "01",
    year: "1990"
    ))
    }
    }
}
  • LabeledContent -- componente nativo do SwiftUI que exibe pares label/valor com alinhamento automático
  • PreviewProvider -- permite visualizar o componente no Xcode Canvas sem executar o app
  • Componentização -- separar em views menores facilita reutilização e testes

A documentação oficial da Apple sobre SwiftUI e gerenciamento de estado detalha os padrões recomendados para @StateObject e @ObservedObject.


Adicionando validação em tempo real

Para uma experiência mais fluida, valide o CPF conforme o usuário digita usando Combine ou o modificador onChange.

import SwiftUI

struct CPFRealtimeView: View {
    @StateObject private var viewModel = CPFViewModel()
    @State private var validacaoLocal: String = ""

    var body: some View {
    Form {
    Section("CPF") {
    TextField("Digite o CPF", text: $viewModel.cpfInput)
    .keyboardType(.numberPad)
    .onChange(of: viewModel.cpfInput) { _, newValue in
    let numeros = newValue.filter { $0.isNumber }
    viewModel.cpfInput = String(numeros.prefix(11))
    validarLocalmente(numeros)
    }

    if !validacaoLocal.isEmpty {
    Text(validacaoLocal)
    .font(.caption)
    .foregroundStyle(
    validacaoLocal.contains("OK") ? .green : .orange
    )
    }
    }

    Section {
    Button("Consultar na API") {
    Task { await viewModel.consultar() }
    }
    .disabled(!validacaoLocal.contains("OK") || viewModel.isLoading)
    }
    }
    }

    private func validarLocalmente(_ cpf: String) {
    if cpf.count < 11 {
    validacaoLocal = "Faltam \(11 - cpf.count) dígitos"
    } else if cpf.isCPFValid {
    validacaoLocal = "Formato OK - pronto para consultar"
    } else {
    validacaoLocal = "Dígitos verificadores inválidos"
    }
    }
}
EstadoFeedback ao usuárioCor
Menos de 11 dígitos"Faltam X dígitos"Laranja
11 dígitos, formato válido"Formato OK"Verde
11 dígitos, formato inválido"Dígitos verificadores inválidos"Laranja
Erro na APIMensagem do erroVermelho
  • Validação progressiva -- feedback instantâneo conforme o usuário digita melhora a experiência
  • Botão desabilitado -- só permite consulta à API quando o CPF passa na validação local
  • Separação de validações -- local (formato) e remota (API) são etapas distintas e complementares

Perguntas frequentes

Como armazenar a API key do CPFHub.io de forma segura em um app SwiftUI?

Adicione a chave como variável no Info.plist via Build Settings > User-Defined e acesse via Bundle.main.object(forInfoDictionaryKey:). Nunca inclua a chave diretamente no código-fonte. Para maior segurança, armazene-a no Keychain após o primeiro acesso e considere um backend proxy para não expor a chave no binário do app.

A API retorna HTTP 429 quando o limite de consultas é atingido?

Não. A CPFHub.io nunca bloqueia requisições nem retorna HTTP 429. Ao atingir o limite do plano, cada consulta adicional é cobrada a R$0,15. O plano gratuito inclui 50 consultas mensais sem cartão de crédito; o plano Pro oferece 1.000 consultas por R$149/mês. Seu código SwiftUI não precisa tratar o status 429.

Como testar o ViewModel sem fazer chamadas reais à API?

Use injeção de dependência no CPFService para substituir a URLSession por uma versão mockada em testes unitários. Crie um protocolo CPFServiceProtocol com o método consultarCPF, implemente um MockCPFService nos testes e injete-o no CPFViewModel. Assim você testa todos os estados (loading, sucesso, erro) sem consumir cota da API.

Qual é a latência da API em um app iOS em produção?

A latência média da API CPFHub.io é de ~900ms. Em apps iOS, considere exibir um ProgressView enquanto a consulta ocorre para evitar a percepção de travamento. O padrão isLoading: Bool no ViewModel já cobre esse caso, e a validação local prévia garante que apenas CPFs com formato correto são enviados à API.


Conclusão

Integrar validação de CPF em um app iOS com SwiftUI é uma experiência fluida quando se combina a reatividade do framework com o padrão MVVM e chamadas assíncronas via async/await. A validação em tempo real fornece feedback imediato, enquanto a consulta à API traz dados reais para confirmar a identidade. Com componentes reutilizáveis e tratamento robusto de erros, seu app estará pronto para produção.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a integrar a validação de CPF no seu app iOS hoje, com latência de ~900ms e zero configuração de servidor.

CPFHub.io

Pronto para integrar a API?

50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

Redação CPFHub.io

Sobre a redação

Redação CPFHub.io

Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.

WhatsAppFale conosco via WhatsApp