JSONSerialization — una clase integrada de iOS del framework Foundation diseñada para convertir JSON en objetos Foundation y viceversa. Esta API es el mecanismo básico para trabajar con JSON en plataformas Apple sin bibliotecas de terceros, compatible con el análisis de diccionarios, matrices y tipos primitivos. Según Apple Developer, 2024, JSONSerialization admite trabajar con Data, flujos y opciones de lectura para el procesamiento flexible de datos JSON.
Puntos clave
JSONSerialization es una clase del framework Foundation disponible en iOS, macOS, tvOS y watchOS. Proporciona métodos para convertir datos JSON en objetos Foundation (NSDictionary, NSArray, NSString, NSNumber) y viceversa. La clase apareció en iOS 5 y hasta la introducción de Codable (Swift 4) siguió siendo la forma principal de trabajar con JSON en plataformas Apple. A pesar de su antigüedad, JSONSerialization sigue siendo relevante en proyectos heredados de Objective-C y en escenarios donde se requiere procesamiento JSON dinámico sin un esquema de modelo fijo.
A pesar de la llegada de Codable, JSONSerialization sigue siendo relevante en varios escenarios. Estructura JSON dinámica — cuando el formato de respuesta cambia o se desconoce de antemano — requiere acceder a diccionarios por claves, lo que es más fácil de hacer con JSONSerialization. La clase también se usa en proyectos Objective-C donde Codable no está disponible, y al trabajar con flujos para análisis incremental de archivos JSON grandes. En pruebas y simulaciones, isValidJSONObject y data(withJSONObject:options:) permiten generar rápidamente fixtures JSON sin bibliotecas de terceros, acelerando el desarrollo y la creación de prototipos.
import Foundation
// Estructura básica de uso de 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("Error de análisis JSON: \(error)")
}
JSONSerialization proporciona cuatro métodos principales para trabajar con JSON. El método principal es jsonObject(with:options:), que convierte Data en objetos Foundation. El método data(withJSONObject:options:) realiza la serialización inversa. isValidJSONObject(_:) verifica si un objeto puede ser serializado. writeJSONObject(_:to:options:error:) escribe JSON directamente en un flujo. Para leer JSON desde InputStream, existe el método jsonObject(with:options:) que acepta un flujo en lugar de Data, lo que es conveniente al integrarse con solicitudes de red que devuelven datos en flujo.
El método jsonObject acepta Data y devuelve Any — normalmente NSDictionary o NSArray. Para un uso seguro, el resultado se convierte al tipo esperado mediante conversión condicional. El método data acepta un objeto Foundation y devuelve Data con una representación JSON. La opción .prettyPrinted agrega formato con sangría para facilitar la lectura.
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("Producto: \(name)")
}
}
}
// Serialización inversa: 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)
}
Análisis básico de un diccionario con tipos primitivos es la operación más común con JSONSerialization. Después de recibir Data a través de URLSession, el desarrollador llama a jsonObject y convierte el resultado al tipo esperado. Para matrices de objetos, se usa la conversión a [[String: Any]], después de lo cual cada elemento se procesa en un bucle. Este enfoque es flexible pero requiere gestión manual de tipos.
Las API reales devuelven objetos JSON anidados complejos con matrices, fechas y campos opcionales. JSONSerialization maneja correctamente cualquier profundidad de anidamiento, pero el desarrollador debe convertir cada nivel al tipo requerido de forma independiente. Para simplificar esta tarea, Apple recomienda usar Codable para datos tipados y JSONSerialization solo para estructuras dinámicas.
// Análisis de respuesta 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("Usuario: \(name) (ID: \(userId))")
} catch let error as ParsingError {
print("Error al analizar: \(error)")
} catch {
print("Error inesperado: \(error)")
}
}
enum ParsingError: Error {
case missingField
case invalidType
}
JSONSerialization lanza errores en caso de JSON no válido, discrepancias de tipos o superación de la profundidad de anidamiento. Los errores pertenecen al tipo CocoaError y contienen un código que describe el problema. El desarrollador debe manejarlos mediante una construcción do-catch, de lo contrario la aplicación fallará. Los errores más comunes son: NSPropertyListReadCorruptError (JSON no válido) y NSPropertyListReadUnknownError. Cada tipo de error requiere su propia estrategia de manejo: para formato no válido, solicitar reenvío de datos, y para discrepancia de estructura, actualizar el modelo de análisis.
JSON no válido — la causa más común de fallos: una coma faltante, un carácter adicional o una comilla sin escapar rompen todo el análisis. El segundo tipo de errores es la discrepancia con la estructura esperada: por ejemplo, el servidor devolvió una matriz en lugar de un diccionario. JSONSerialization.fragmentsAllowed permite leer JSON cuya raíz no es un diccionario o matriz sino un valor primitivo. El desarrollador también puede encontrarse con un error de profundidad de anidamiento excedida cuando JSON contiene demasiados niveles de jerarquía.
JSONSerialization proporciona varias opciones para configurar el análisis. .mutableContainers devuelve NSMutableDictionary y NSMutableArray en lugar de versiones inmutables, lo que es útil al modificar datos después del análisis. .mutableLeaves hace modificables los valores de cadena. .fragmentsAllowed permite JSON cuya raíz no es un objeto o matriz sino una cadena o número — conveniente para respuestas API simples. Las opciones .withoutEscapingSlashes y .sortedKeys están disponibles para el método data(withJSONObject:options:), controlando el formato del JSON serializado. Las opciones se pasan como una máscara de bits, lo que permite combinar varios valores mediante el operador | para una configuración flexible del análisis.
// Manejo de varios tipos de errores
func safeParse(jsonData: Data) {
do {
let object = try JSONSerialization
.jsonObject(with: jsonData,
options: .fragmentsAllowed)
if let dictionary = object as? [String: Any] {
print("Diccionario con \(dictionary.count) claves")
} else if let array = object as? [Any] {
print("Array con \(array.count) elementos")
}
} catch CocoaError.propertyListReadCorrupt {
print("Datos JSON corruptos")
} catch let error as CocoaError {
print("Error de Cocoa: \(error)")
} catch {
print("Error desconocido: \(error)")
}
}
// Verificación de validez del objeto antes de la serialización
let testObject: [String: Any] = ["key": "value", "nested": ["a": 1]]
if JSONSerialization.isValidJSONObject(testObject) {
print("Objeto JSON válido")
}
El rendimiento de JSONSerialization depende del tamaño de los datos y la frecuencia de las llamadas. Para un análisis único de una respuesta pequeña del servidor, la diferencia es insignificante, pero al procesar decenas de megabytes de JSON o llamadas frecuentes en bucles, se debe considerar la sobrecarga de la conversión de tipos. JSONSerialization funciona de forma sincrónica en el hilo actual, por lo que para documentos grandes se recomienda mover el análisis a una cola en segundo plano mediante DispatchQueue.global(). Alternativamente, puede usar InputStream para procesamiento en flujo sin cargar todo el archivo en memoria, lo que es crítico para aplicaciones con recursos limitados. Para escribir JSON en un archivo o flujo de red, el método writeJSONObject(_:to:options:error:) permite enviar datos serializados directamente a OutputStream sin crear un objeto Data intermedio, reduciendo el consumo de memoria al trabajar con documentos grandes.
Preguntas frecuentes
JSONSerialization es una clase de Foundation para convertir datos JSON en objetos Foundation (NSDictionary, NSArray) y viceversa. Funciona en iOS, macOS, tvOS y watchOS sin bibliotecas adicionales.
Codable es un protocolo de Swift para serialización tipada automática que se compila en código seguro en cuanto a tipos. JSONSerialization trabaja con tipos dinámicos Any y requiere conversión manual. Codable es preferible para proyectos nuevos, JSONSerialization para Objective-C y datos dinámicos.
Use la construcción do-catch al llamar a jsonObject. Los errores de JSONSerialization pertenecen a CocoaError. Para depuración, verifique NSPropertyListReadCorruptError, que indica un formato de datos JSON no válido.
Sí, JSONSerialization admite cualquier profundidad de anidamiento de diccionarios y matrices. Todos los objetos anidados se convierten a los tipos Foundation correspondientes (NSDictionary, NSArray, NSString, NSNumber), preservando la estructura JSON original.
JSONSerialization es apropiado para estructuras JSON dinámicas, en proyectos Objective-C, al trabajar con flujos y para validar JSON mediante isValidJSONObject. Para estructuras tipadas con un esquema conocido, Codable es preferible.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también