La deserialización es el proceso de restaurar un objeto a partir de un flujo de datos JSON, XML o Protobuf, esencial para cualquier aplicación móvil que funcione con una API remota. Según Apple Developer (2026), el manejo incorrecto de los datos entrantes sigue siendo una de las causas comunes de fallos en los dispositivos. JSONDecoder en iOS y Gson en Android son herramientas estándar, pero cada una tiene sus propias características y limitaciones.
Puntos clave
Deserialización es el proceso de convertir un flujo de bytes o texto estructurado en un objeto de lenguaje de programación. En el desarrollo móvil, este proceso ocurre cada vez que una aplicación recibe una respuesta del servidor: una cadena JSON se convierte en una instancia de la clase User, Order o Product. La estabilidad de las pantallas que muestran datos al usuario depende directamente de la corrección de la deserialización.
La serialización y la deserialización son procesos mutuamente inversos, raramente simétricos en la práctica. Serialización convierte un objeto en una cadena para enviarla al servidor, mientras que la deserialización restaura el objeto a partir de la cadena recibida. El servidor puede enviar un campo que no existe en el modelo del cliente, usar un formato de fecha diferente o devolver null en lugar de un número. Según Square Engineering (2025), la asimetría de formatos causa el 23% de los errores de la capa de red en aplicaciones Android. Para reducir el riesgo, se utilizan el versionado de esquemas y la especificación de contratos estrictos mediante OpenAPI.
JSON sigue siendo el formato más popular para APIs móviles gracias a su legibilidad humana y soporte nativo. Protobuf de Google se utiliza en sistemas de alta carga: es de 3 a 6 veces más compacto que JSON y se analiza más rápido, pero requiere generación de código a partir de archivos .proto y no es legible sin herramientas. XML es menos común en aplicaciones móviles modernas, aunque se utiliza en servicios SOAP de sistemas empresariales y archivos de configuración de Android. MessagePack es un formato binario similar a JSON en estructura pero más compacto, popular en sistemas de tiempo real.
El proceso de deserialización pasa por tres etapas. Primero, la tokenización divide el texto bruto en tokens: claves, cadenas, números y delimitadores. Luego, el análisis sintáctico verifica la corrección de la estructura — si los corchetes están cerrados, si el tipo de comillas es correcto, si el formato cumple con RFC 8259. La etapa final es el mapeo al modelo de objetos de la aplicación, donde a cada clave JSON se le asigna una propiedad de clase teniendo en cuenta la estrategia de nomenclatura.
En el desarrollo móvil han surgido dos enfoques para el mapeo. Reflection (Gson, JSONSerialization) analiza la estructura de la clase en tiempo de ejecución a través de Java Reflection API o del runtime de Objective-C: es flexible y no requiere configuración adicional, pero es más lento y consume más memoria. Code generation (Moshi codegen, kotlinx.serialization, Codable) genera código en tiempo de compilación: es más rápido, más seguro en tipos y no expone la estructura interna mediante reflection. JetBrains y Square recomiendan la generación de código para compilaciones de producción: las ganancias de rendimiento alcanzan 2-4 veces en los benchmarks de Google.
struct User: Codable {
let id: Int
let name: String
let email: String
let createdAt: Date
}
let json = """
{
"id": 42,
"name": "Alice",
"email": "alice@example.com",
"created_at": "2026-06-01T12:00:00Z"
}
"""
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let user = try decoder.decode(User.self, from: data)
Ejemplo de deserialización de JSON en un modelo User en Swift. La estrategia convertFromSnakeCase convierte automáticamente las claves API en snake_case a propiedades del modelo en camelCase — una práctica estándar en proyectos iOS. El parámetro data son los bytes brutos de la respuesta del servidor obtenidos a través de URLSession. El manejo de errores mediante try permite capturar JSON malformado sin bloquear la aplicación.
JSONDecoder admite cuatro estrategias de claves: useDefaultKeys (coincidencia exacta), convertFromSnakeCase (snake_case → camelCase), custom (closure) y convertFromKebabCase (kebab-case → camelCase). Para las fechas están disponibles .iso8601, .secondsSince1970, .millisecondsSince1970 y un dateFormatter personalizado. Elegir la estrategia correcta es el primer paso hacia una deserialización robusta, evitando la mayoría de los errores de desajuste de formatos.
JSONDecoder es el mecanismo estándar de deserialización en el SDK de iOS, que funciona con el protocolo Codable. JSONDecoder analiza automáticamente JSON en instancias de struct o class, soportando objetos anidados, arrays y primitivos. Para lógica personalizada se utiliza el método init(from: Decoder) — permite manejar formatos no estándar, campos faltantes en una versión antigua de la API o combinar varias claves JSON en una sola propiedad.
struct Order: Decodable {
let orderId: String
let amount: Double
let status: OrderStatus
enum OrderStatus: String, Decodable {
case pending, confirmed, shipped, cancelled
}
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let order = try decoder.decode(Order.self, from: jsonData)
DateDecodingStrategy determina cómo JSONDecoder interpreta las cadenas de fecha. .iso8601 es el más utilizado — el formato estándar de las API REST. El enum anidado OrderStatus se decodifica automáticamente a partir de valores de cadena JSON. Esto evita números mágicos y hace que el código sea autodocumentado: el estado del pedido siempre tiene un conjunto de valores estrictamente definido.
Desde Swift 4.2, Codable admite property wrappers para la deserialización personalizada de propiedades individuales. @DefaultValue es un wrapper popular que asigna un valor por defecto si el campo falta en el JSON. @LosslessString convierte una cadena en un número y viceversa. Esto es especialmente útil cuando el servidor envía un id como la cadena "123" pero el modelo espera un Int. Los property wrappers reducen el código repetitivo en init(from:) y hacen que los modelos sean más limpios.
En Android, la elección de la biblioteca de deserialización depende del idioma y los requisitos del proyecto. Gson de Google es la opción más común, que funciona mediante reflection pero tiene problemas de rendimiento con jerarquías complejas. Moshi de Square admite tanto reflection como code generation, consumiendo menos memoria y procesando respuestas grandes más rápido. kotlinx.serialization de JetBrains es una solución nativa de Kotlin con integración en el compilador que no utiliza reflection en absoluto.
@Serializable
data class User(
@SerialName("user_id")
val userId: Int,
val name: String,
val email: String,
@SerialName("created_at")
val createdAt: String
)
val json = Json { ignoreUnknownKeys = true }
val user = json.decodeFromString<User>(response)
@Serializable es una anotación del compilador de Kotlin que activa la generación de código para la clase. El parámetro ignoreUnknownKeys evita fallos si el servidor envía un campo que falta en el modelo. Para el mapeo de claves snake_case se utiliza @SerialName — el equivalente de convertFromSnakeCase de iOS. Según JetBrains (2026), la biblioteca admite multiplataforma: la misma clase Serializable funciona en Android, iOS (KMP) y Kotlin del lado del servidor.
La elección entre bibliotecas se reduce a un compromiso entre velocidad y flexibilidad. Gson es bueno para prototipos y proyectos en Java: no requiere anotaciones y funciona de serie. Moshi ocupa una posición intermedia: codegen mediante @JsonClass(generateAdapter = true) ofrece una velocidad cercana a kotlinx.serialization, mientras que el modo reflection proporciona la flexibilidad de Gson. kotlinx.serialization es la opción más rápida para proyectos puramente Kotlin, pero requiere Kotlin 1.4+ y el plugin Kotlin Serialization en Gradle.
| Biblioteca | Mecanismo | Velocidad | KMP |
|---|---|---|---|
| Gson | Reflection | Baja | No |
| Moshi | Reflection / Codegen | Media / Alta | No |
| kotlinx.serialization | Codegen del compilador | Alta | Sí |
Type mismatch es una situación en la que JSON contiene un valor de un tipo pero el modelo espera otro. El servidor envió la cadena "42" en lugar de un número, o el número 1 en lugar de un booleano true. En iOS, JSONDecoder lanzará DecodingError.typeMismatch por defecto; en Android, Gson intentará la conversión, mientras que Moshi y kotlinx.serialization requieren adaptadores explícitos. La solución es usar estrategias lenient o deserializadores personalizados para campos específicos.
Cuando el servidor no incluye un campo opcional, el código falla con un error. Los campos Optional en Swift y los tipos nullable en Kotlin resuelven el problema: si el campo es null o falta en el JSON, la propiedad obtiene nil/null y la aplicación continúa funcionando. Para los campos obligatorios, vale la pena verificar su presencia a nivel del cliente API antes de la deserialización. Moshi y kotlinx.serialization requieren todos los campos por defecto — el marcado nullable y los valores por defecto eliminan esta restricción.
Los cambios en la estructura JSON en el servidor son una fuente común de fallos en producción. La práctica estándar es el versionado de esquemas mediante un campo version en el objeto raíz y el soporte de 2-3 versiones anteriores en el cliente. kotlinx.serialization permite declarar varios modelos para diferentes versiones y seleccionar el adecuado según el campo version después del análisis inicial en JsonElement. La protección adicional incluye ignoreUnknownKeys para campos nuevos y valores por defecto para campos que pueden ser eliminados.
| Error | Síntoma | Biblioteca con protección |
|---|---|---|
| Type mismatch | DecodingError / Excepción | kotlinx — coerceInputValues = true |
| Campo faltante | Fallo al acceder | Moshi — @Transient + default |
| Formato de fecha incorrecto | Error de decodificación | JSONDecoder — dateDecodingStrategy |
| Campos extra | Ignorados o fallo | kotlinx — ignoreUnknownKeys = true |
| Null en campo no nullable | Fallo en runtime | Moshi — lenient con @Nullable |
Registro de errores de deserialización es una práctica obligatoria en producción. Envuelve decode en do/catch, registra el JSON bruto y el tipo de modelo esperado en Crashlytics o Sentry. Esto permitirá identificar rápidamente qué campo de qué API se rompió y en qué versión de la aplicación. Sin registro, un error de deserialización parece un fallo misterioso sin contexto.
Preguntas frecuentes
El parsing es el análisis de texto estructurado en elementos constituyentes sin crear necesariamente un modelo tipificado. La deserialización es un caso específico de parsing cuyo resultado es un objeto de lenguaje completo con tipos de propiedades conocidos. El parsing puede ser por flujo, la deserialización siempre crea un objeto completo.
Para un proyecto en Kotlin puro se recomienda kotlinx.serialization — está integrada en el compilador, no usa reflection y soporta Kotlin Multiplatform. Para un proyecto Java existente — Moshi con code generation. Gson es mejor dejarlo para proyectos heredados donde su reemplazo requeriría un esfuerzo significativo.
En iOS, usa keyDecodingStrategy = .convertFromSnakeCase en JSONDecoder. En Android con kotlinx.serialization, usa @SerialName para cada campo. En Moshi, aplica @Json(name="field_name") o un JsonAdapter.Factory global. Un estilo coherente a nivel de proyecto es una buena práctica acordada en el contrato de la API.
La razón más común es un null inesperado del servidor en un campo declarado como obligatorio. En desarrollo, el servidor devuelve datos completos; en producción, devuelve una respuesta reducida. La solución: marcar todos los campos potencialmente ausentes como nullable (Kotlin) u optional (Swift), usar ignoreUnknownKeys y valores por defecto.
Code generation (Moshi codegen, kotlinx.serialization, Codable) funciona de 2 a 4 veces más rápido que reflection en los benchmarks de Google. Además de velocidad, la generación de código es más segura en tipos, no requiere metadatos de clases en tiempo de ejecución y los errores de tipo se detectan en tiempo de compilación, no durante la deserialización.
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