JSONSerialization — uma classe integrada do iOS do framework Foundation projetada para converter JSON em objetos Foundation e vice-versa. Esta API é o mecanismo básico para trabalhar com JSON nas plataformas Apple sem bibliotecas de terceiros, suportando parsing de dicionários, arrays e tipos primitivos. De acordo com Apple Developer, 2024, JSONSerialization suporta trabalhar com Data, fluxos e opções de leitura para processamento flexível de dados JSON.
Principais conclusões
JSONSerialization é uma classe do framework Foundation disponível no iOS, macOS, tvOS e watchOS. Ela fornece métodos para converter Data JSON em objetos Foundation (NSDictionary, NSArray, NSString, NSNumber) e vice-versa. A classe apareceu no iOS 5 e até a introdução do Codable (Swift 4) permaneceu a principal forma de trabalhar com JSON nas plataformas Apple. Apesar da idade, o JSONSerialization continua relevante em projetos legados Objective-C e em cenários onde é necessário processamento JSON dinâmico sem um esquema de modelo fixo.
Apesar do advento do Codable, o JSONSerialization continua relevante em vários cenários. Estrutura JSON dinâmica — quando o formato da resposta muda ou é desconhecido antecipadamente — requer acesso a dicionários por chaves, o que é mais fácil de fazer através do JSONSerialization. A classe também é usada em projetos Objective-C onde o Codable não está disponível e ao trabalhar com fluxos para parsing incremental de grandes arquivos JSON. Em testes e simulações, isValidJSONObject e data(withJSONObject:options:) permitem gerar rapidamente fixtures JSON sem bibliotecas de terceiros, acelerando o desenvolvimento e prototipagem.
import Foundation
// Estrutura básica de uso do JSONSerialization
let jsonString = """
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
"""
guard let jsonData = jsonString.data(using: .utf8) else {
return
}
do {
let json = try JSONSerialization
.jsonObject(with: jsonData,
options: .mutableContainers)
print(json)
} catch {
print("Erro de parsing JSON: \(error)")
}
JSONSerialization fornece quatro métodos principais para trabalhar com JSON. O método principal é jsonObject(with:options:), que converte Data em objetos Foundation. O método data(withJSONObject:options:) realiza a serialização reversa. isValidJSONObject(_:) verifica se um objeto pode ser serializado. writeJSONObject(_:to:options:error:) escreve JSON diretamente em um fluxo. Para ler JSON de InputStream, existe o método jsonObject(with:options:) que aceita um fluxo em vez de Data, o que é conveniente ao integrar com requisições de rede que retornam dados em fluxo.
O método jsonObject aceita Data e retorna Any — normalmente NSDictionary ou NSArray. Para uso seguro, o resultado é convertido para o tipo esperado através de conversão condicional. O método data aceita um objeto Foundation e retorna Data com uma representação JSON. A opção .prettyPrinted adiciona formatação com indentação para legibilidade.
let jsonString = """
{
"products": [
{"id": 1, "name": "iPhone", "price": 999},
{"id": 2, "name": "iPad", "price": 799}
]
}
"""
let data = Data(jsonString.utf8)
if let json = try? JSONSerialization
.jsonObject(with: data) as? [String: Any],
let products = json["products"] as? [[String: Any]] {
for product in products {
if let name = product["name"] as? String {
print("Produto: \(name)")
}
}
}
// Serialização reversa: objeto -> JSON
let outputDict: [String: Any] = ["status": "ok", "count": 42]
if let outputData = try? JSONSerialization
.data(withJSONObject: outputDict,
options: .prettyPrinted) {
String(data: outputData, encoding: .utf8)
}
Parsing básico de um dicionário com tipos primitivos é a operação mais comum com JSONSerialization. Após receber Data via URLSession, o desenvolvedor chama jsonObject e converte o resultado para o tipo esperado. Para arrays de objetos, usa-se conversão para [[String: Any]], após a qual cada elemento é processado em um loop. Essa abordagem é flexível, mas requer gerenciamento manual de tipos.
APIs reais retornam objetos JSON aninhados complexos com arrays, datas e campos opcionais. JSONSerialization lida corretamente com qualquer profundidade de aninhamento, mas o desenvolvedor deve converter cada nível para o tipo necessário de forma independente. Para simplificar essa tarefa, a Apple recomenda usar Codable para dados tipados e JSONSerialization apenas para estruturas dinâmicas.
// Parsing de resposta de API
func parseUserResponse(data: Data) {
do {
guard let json = try JSONSerialization
.jsonObject(with: data) as? [String: Any]
else { return }
guard let userId = json["id"] as? Int,
let name = json["name"] as? String
else {
throw ParsingError.missingField
}
print("Usuário: \(name) (ID: \(userId))")
} catch let error as ParsingError {
print("Falha no parsing: \(error)")
} catch {
print("Erro inesperado: \(error)")
}
}
enum ParsingError: Error {
case missingField
case invalidType
}
JSONSerialization lança erros em caso de JSON inválido, incompatibilidade de tipos ou excesso de profundidade de aninhamento. Os erros pertencem ao tipo CocoaError e contêm um código que descreve o problema. O desenvolvedor deve tratá-los através de uma construção do-catch, caso contrário o aplicativo travará. Os erros mais comuns são: NSPropertyListReadCorruptError (JSON inválido) e NSPropertyListReadUnknownError. Cada tipo de erro requer sua própria estratégia de tratamento: para formato inválido, solicitar reenvio de dados e, para incompatibilidade de estrutura, atualizar o modelo de parsing.
JSON inválido — a causa mais comum de falhas: uma vírgula ausente, caractere extra ou aspas sem escape quebra todo o parsing. O segundo tipo de erro é incompatibilidade com a estrutura esperada: por exemplo, o servidor retornou um array em vez de um dicionário. JSONSerialization.fragmentsAllowed permite ler JSON cuja raiz não é um dicionário ou array, mas um valor primitivo. O desenvolvedor também pode encontrar um erro de profundidade de aninhamento excedida quando o JSON contém muitos níveis hierárquicos.
JSONSerialization fornece várias opções para configurar o parsing. .mutableContainers retorna NSMutableDictionary e NSMutableArray em vez de versões imutáveis, o que é útil ao modificar dados após o parsing. .mutableLeaves torna os valores de string mutáveis. .fragmentsAllowed permite JSON cuja raiz não é um objeto ou array, mas uma string ou número — conveniente para respostas de API simples. As opções .withoutEscapingSlashes e .sortedKeys estão disponíveis para o método data(withJSONObject:options:), controlando a formatação do JSON serializado. As opções são passadas como uma máscara de bits, permitindo combinar vários valores através do operador | para configuração flexível de parsing.
// Tratamento de vários tipos de erros
func safeParse(jsonData: Data) {
do {
let object = try JSONSerialization
.jsonObject(with: jsonData,
options: .fragmentsAllowed)
if let dictionary = object as? [String: Any] {
print("Dicionário com \(dictionary.count) chaves")
} else if let array = object as? [Any] {
print("Array com \(array.count) itens")
}
} catch CocoaError.propertyListReadCorrupt {
print("Dados JSON corrompidos")
} catch let error as CocoaError {
print("Erro Cocoa: \(error)")
} catch {
print("Erro desconhecido: \(error)")
}
}
// Verificação de validade do objeto antes da serialização
let testObject: [String: Any] = ["key": "value", "nested": ["a": 1]]
if JSONSerialization.isValidJSONObject(testObject) {
print("Objeto JSON válido")
}
O desempenho do JSONSerialization depende do tamanho dos dados e da frequência das chamadas. Para um único parsing de uma resposta pequena do servidor, a diferença é insignificante, mas ao processar dezenas de megabytes de JSON ou chamadas frequentes em loops, a sobrecarga da conversão de tipos deve ser considerada. JSONSerialization funciona de forma síncrona na thread atual, portanto, para documentos grandes, recomenda-se mover o parsing para uma fila em segundo plano através de DispatchQueue.global(). Alternativamente, você pode usar InputStream para processamento em fluxo sem carregar o arquivo inteiro na memória, o que é crítico para aplicativos com recursos limitados. Para escrever JSON em um arquivo ou fluxo de rede, o método writeJSONObject(_:to:options:error:) permite enviar dados serializados diretamente para OutputStream sem criar um objeto Data intermediário, reduzindo o consumo de memória ao trabalhar com documentos grandes.
Perguntas frequentes
JSONSerialization é uma classe Foundation para converter Data JSON em objetos Foundation (NSDictionary, NSArray) e vice-versa. Funciona no iOS, macOS, tvOS e watchOS sem bibliotecas adicionais.
Codable é um protocolo Swift para serialização tipada automática que compila em código type-safe. JSONSerialization trabalha com tipos dinâmicos Any e requer conversão manual. Codable é preferível para novos projetos, JSONSerialization para Objective-C e dados dinâmicos.
Use a construção do-catch ao chamar jsonObject. Erros de JSONSerialization pertencem ao CocoaError. Para depuração, verifique NSPropertyListReadCorruptError, que indica um formato de dados JSON inválido.
Sim, JSONSerialization suporta qualquer profundidade de aninhamento de dicionários e arrays. Todos os objetos aninhados são convertidos nos tipos Foundation correspondentes (NSDictionary, NSArray, NSString, NSNumber), preservando a estrutura JSON original.
JSONSerialization é adequado para estruturas JSON dinâmicas, em projetos Objective-C, ao trabalhar com fluxos e para validar JSON através de isValidJSONObject. Para estruturas tipadas com um esquema conhecido, Codable é preferível.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também