Background Image
TECNOLOGÍA

Cómo depurar NSLayout- Restricciones (LayoutBeast)

Julian Builes

Consultor principal
Asset - Julian Builes Photo for profile

January 18, 2023 | 7 Minuto(s) de lectura

Al escribir aplicaciones iOS, pocas cosas son más frustrantes (y más comunes) que los conflictos de diseño automático. Te tomas el tiempo para visualizar tu hermoso diseño, crear una imagen mental de la jerarquía de vistas, y tal vez incluso esbozar un bonito dibujo...

Asset - How To Debug NSLayoutConstraints (LayoutBeast) blog photo 1

Pero una vez que compilas y ejecutas tu aplicación, ¡BOOM! te explota en la cara y las cosas no se ven como esperabas. Ahora te estás rascando la cabeza, y todo lo que te queda son algunos registros de diseño crípticos que pueden ser intimidantes y aterradores de leer. ¿Le resulta familiar? No se preocupe, estoy aquí para ayudarle.

Puedo prometerte que después de invertir unos minutos en este artículo, verás que las cosas no están tan mal después de todo: sobrevivirás, la vida seguirá, y serás capaz de depurar conflictos de diseño como un profesional en poco tiempo. Bien, ahora que ya nos hemos quitado eso de encima, ¡vamos a entrar en materia!

Tipos de errores de diseño

Insatisfactible

Hay información contradictoria/confusa en tu lógica de diseño.

  • Ej: Una restricción dice "hacer ancho 400", pero otra restricción dice, "bueno, en realidad hacer ancho 325".

Ambiguo

No hay suficiente información de maquetación para resolver las restricciones.

  • Ejemplo: La lógica dice "anchura 200, coordenada x 0, coordenada y 25", pero olvidaste especificar la altura.

Lógico

Hay un error en tu layout.

  • Ej: haz la vista 35 puntos más grande que la vista padre, pero olvidaste especificar cuál es la vista padre.

Comprobaciones de cordura

Comprueba mentalmente estas casillas antes de empezar a depurar:

1. 1. ¿Se ha ejecutado correctamente toda la lógica de diseño?

  • El diseño de una vista puede depender de que se calcule una dimensión específica o de que se configure correctamente una vista ya existente.

  • Es posible que algunos diseños deban especificarse en un orden determinado. Si es así, asegúrate de que lo sabes y de que el orden de los eventos es correcto. Añadir subvistas a una stackView es un buen ejemplo de esto.

2. ¿Has configurado translatesAutoresizingMaskIntoConstraints a false al añadir restricciones mediante programación?

  • El Interface Builder lo establecerá automáticamente en no si añade restricciones en el lienzo, pero eso no ocurrirá cuando añada restricciones mediante programación.

  • CONSEJO: Verá que NSAutoresizingMaskLayoutConstraint en una de sus restricciones en conflicto en los registros.

3. ¿Está completa la jerarquía de vistas?

  • Asegúrese de que ha instanciado las vistas padre, y que las vistas hijas se añaden a la padre como subvistas apropiadamente.

4. ¿Estás añadiendo restricciones tanto programáticamente como en los Storyboards?

  • Trato de evitar esto tanto como puedo. Como los storyboards tienden a hacer cosas mágicas de las que a veces no soy consciente, mientras que programáticamente eres responsable de cada paso. Esto hace que las cosas sean un poco más difíciles de depurar.

Leyendo Registros de Conflictos de Restricciones

AutoLayout to plain dummy Traductor Inglés

Las restricciones se aplican a una vista y pueden ser relativas a otra vista (hacer la altura de una vista igual a otra), o pueden establecer una dimensión con un número fijo (hacer la altura 162).

¿Qué información busca en cada restricción? 

  • La vista principal a la que se aplica

  • La dimensión (alto, ancho, delante, detrás, arriba, abajo)

  • La orientación (vertical u horizontal)

  • Una vista secundaria con la que está relacionada la restricción (opcional)

  • La restricción es constante. El número real a aplicar a la restricción. Éste también puede ser negativo.

Ejemplos:

<NSLayoutConstraint:0x60000041c0f0 UIImageView:0x7fb5af855ea0.height == 164 (active)>

  • Establecer la altura de UIImageView a 164 puntos.

<NSLayoutConstraint:0x60000041c910 V:|-(9)-[UIStackView:0x7fb5af855810] (active, names: '|':UIView:0x7fb5af854ec0 )>

  • Aplicar un espacio vertical de 9 puntos entre stackView y view.

<NSLayoutConstraint:0x60000041caa0 MyApp.FeaturedCollectionViewCell:0x7fb5af855bf0.top == UIView:0x7fb5af854ec0.top (active)>

  • Hacer que la parte superior de FeaturedCollectionViewCell (clase de celda personalizada) igual a la parte superior de la vista.

<NSLayoutConstraint:0x6000004b2350 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x600001ec7aa0'UIViewLayoutMarginsGuide']-(10)-| (active, names: '|':UIStackView:0x7fb59fd07360 )>

  • SEl borde inferior de stackView debe ser igual a la guía de diseño inferior de la vista más 10 puntos.

Un ejemplo real

(vamos a caminar)

Ahora que tenemos algo de preparación, ¿cómo podemos solucionar algunos problemas reales de restricciones en el mundo real? He creado un proyecto simple que puedes descargar aquí para depurar 2 restricciones diferentes.

Bienvenido a LayoutBeast (descárgalo aquí), una sencilla aplicación de Xcode con 1 controlador de vista y 4 subvistas: blueView, blueLabel , orangeView, orangeLabel.

Asset - How To Debug NSLayoutConstraints (LayoutBeast) Blog Photo 2

Sin embargo, si ejecutas la aplicación, verás que tenemos algunos problemas. Echemos un vistazo:

Ejemplo #1

2022-10-04 10:42:27.022723-0400 LayoutBeast[98234:4811764] [LayoutConstraints] No se pueden satisfacer simultáneamente las restricciones.

Probablemente al menos una de las restricciones de la siguiente lista es una que no quieres.

Inténtelo:

  1. Mira cada restricción e intenta averiguar cuál es la que no esperas;

  2. Encuentra el código que ha añadido la restricción o restricciones no deseadas y corrígelo.

(NOTA: Si está viendo NSAutoresizingMaskLayoutConstraints que no entiendes, consulta la documentación de la propiedad UIView translatesAutoresizingMaskIntoConstraints)

Ejemplo #2

( "<NSAutoresizingMaskLayoutConstraint:0x60000236d4a0 h=--& v=--& an orange view.width == 0 (active, names: an orange view:0x7f796ff0bf90 )>", "<NSLayoutConstraint:0x6000023647d0 an orange view.width == 100 (active, names: an orange view:0x7f796ff0bf90 )>" )

Éste no está tan mal. Podemos ver que tenemos algunas NSAutoresizingMaskLayoutConstraints a una de nuestras vistas. Si echamos un vistazo a la nota en los logs, podemos ver una buena pista ahí... También hablamos de esto en nuestra sección de sanity check, punto 2.

El problema parece ser que no establecimos translatesAutoresizingMaskIntoConstraints a false en una de nuestras vistas. La solución será añadir esta línea a nuestro método configureOrangeView() para

orangeView.translatesAutoresizingMaskIntoConstraints = false

Ahh, ¡todo bien ahora! Las cosas están mucho mejor ahora. Y también se ven mejor:

Asset - How To Debug NSLayoutConstraints (LayoutBeast) Blog Photo 3

Causalidad vs Correlación

Usted puede haber notado advertencias icono púrpura que aparece en un par de lugares en Xcode. Se trata de advertencias en tiempo de ejecución que indican problemas de diseño. Este es otro lugar donde se puede obtener información útil acerca de dónde se están produciendo violaciones. Sin embargo, a veces pueden ser un poco engañosas. En este escenario específico, por ejemplo, estas advertencias son NO le indican quién es el responsable (causalidad), sino qué otras vistas se están viendo afectadas (correlación).

Asset - How To Debug NSLayoutConstraints (LayoutBeast) blog photo 4

Además, si ha ejecutado el proyecto, es posible que haya observado otros problemas de restricciones en nuestros registros, justo debajo del que hemos citado anteriormente. Estos también indicaban vistas y restricciones afectadas, pero NO ERAN la causa raíz.

Se trata de hacer una distinción importante, no sólo aplicable a las restricciones, sino a la ingeniería en general:

Su trabajo es siempre encontrar la causa raíz. El núcleo del problema. Intentar resolver cualquier cosa por encima de eso no resolverá el problema original y más profundo.

CONSEJO: Mirando más de cerca los registros de error anteriores, verá "una vista naranja" en las restricciones ofensivas. Extraño ... Tras una inspección más cercana, se le también ver que estamos estableciendo el accessibilityIdentifier para la vista orangeView a ese texto. Esto significa, que usted puede establecer el identificador de accesibilidad para una vista para que se imprima cuando usted consigue los conflictos de restricción. ¡Esto ha sido SUPER SUPER útil para mí!

¿Tienes alguna pregunta sobre esta entrada de blog? Envía un correo al autor a julian.builes@improving.com o ponte en contacto con Improving aquí¡! Si eres un desarrollador en busca de oportunidades profesionales, echa un vistazo a nuestra página de empleo.

Tecnología
Application Modernization

Reflexiones más recientes

Explore las entradas de nuestro blog e inspírese con los líderes de opinión de todas nuestras empresas.
Blog Image - Unveiling the Future of AI at Google Cloud Next 24 -1
IA/ML

Unveiling the Future of AI at Google Cloud Next ‘24

Get firsthand insights from Improving into the innovation brewing around artificial intelligence and cloud computing at Google Cloud Next '24.