Después de Xcode 11.2: la aplicación falla debido a _UITextLayoutView — solución

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Después de actualizar Xcode 11.2 la aplicación falla: cómo vencer a _UITextLayoutView

\n\n

¿Te pasa esto? Estás trabajando tranquilamente en tu proyecto, todo vuela, las pruebas pasan, los usuarios están contentos. Y de repente — ¡pum! — actualizas Xcode a la versión 11.2, ejecutas la aplicación y falla con un misterioso error _UITextLayoutView. ¿Te suena? Si es así, no estás solo. Este problema literalmente explotó Stack Overflow a finales de 2019 (miles de visitas en una semana).

\n\n

En este artículo no solo te mostraré cómo corregir este error, sino que también explicaré por qué ocurre, cómo diagnosticarlo y, lo más importante, cómo prevenirlo en el futuro. Lo analizaremos todo con ejemplos prácticos en Swift. ¡Allá vamos!

\n\n

¿Qué clase de bicho es _UITextLayoutView?

\n\n

Empecemos con la teoría. _UITextLayoutView es una clase interna (privada) de UIKit que se encarga de renderizar texto en UITextView. Apple no la documenta públicamente, por lo que cuando algo salió mal con esta clase en Xcode 11.2, los desarrolladores quedaron en un callejón sin salida. El error se ve más o menos así:

\n\n
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_UITextLayoutView setFrame:]: unrecognized selector sent to instance 0x...'
\n\n

La frase clave es "unrecognized selector sent to instance". Esto significa que estás intentando llamar al método setFrame: en un objeto que no lo soporta. Y como _UITextLayoutView es una clase privada, antes de Xcode 11.2 se comportaba de manera diferente.

\n\n

¿Quién está en el grupo de riesgo?

\n\n

El problema no se manifiesta en todos, solo bajo ciertas condiciones. Este es el escenario típico:

\n
    \n
  • Usas UITextView con el cambio automático de tamaño (auto-sizing) activado.
  • \n
  • Tienes una jerarquía de vistas personalizada donde UITextView está anidado en un UIScrollView o UITableViewCell.
  • \n
  • Interactúas activamente con el campo de texto: desplazas, editas, cambias la fuente.
  • \n
\n\n

Si al menos un punto coincide — felicidades, estás en la zona de riesgo. Pero no te preocupes: hay solución, y es elegante.

\n\n

Paso 1: Diagnóstico — encuentra al culpable

\n\n

Antes de tratar, asegurémonos de que el problema es realmente _UITextLayoutView. Abre la consola de Xcode (View → Debug Area → Activate Console) y ejecuta la aplicación. Si ves un error similar al que mostré arriba, estás en el camino correcto.

\n\n

Una señal adicional: el fallo ocurre en el primer intento de mostrar el UITextView o al desplazarte dentro de él. Si la aplicación falla inmediatamente después de cargar, probablemente sea esto.

\n\n

Paso 2: Solución simple y rápida (para los que tienen prisa)

\n\n

La corrección más popular en Stack Overflow es desactivar el cambio automático de tamaño en UITextView. Así se hace:

\n\n
// En tu viewDidLoad o método de configuración\ntextView.isScrollEnabled = false\ntextView.translatesAutoresizingMaskIntoConstraints = true
\n\n

¡Pero atención! Esta solución funciona, pero rompe el autoajuste del texto. Si es crítico para ti que UITextView cambie dinámicamente su altura según el contenido, esta opción no servirá. Vamos a profundizar más.

\n\n

Paso 3: Solución avanzada — sobrescribir layoutSubviews

\n\n

Apple lanzó un parche en Xcode 11.2.1, pero si por alguna razón te quedaste en la versión 11.2, o quieres una solución universal, esto es lo que debes hacer.

\n\n

Crea una subclase de UITextView y sobrescribe el método layoutSubviews:

\n\n
import UIKit\n\nclass FixedTextView: UITextView {\n    override func layoutSubviews() {\n        super.layoutSubviews()\n        // Limpiamos la capa de subvistas sobrantes que causa el error\n        self.subviews.forEach { subview in\n            if subview.isKind(of: NSClassFromString("_UITextLayoutView") ?? UIView.self) {\n                

Blogs

Book Recommendations