El área de depuración es una característica útil en el trabajo de los desarrolladores de iOS en Xcode. Tan pronto como comencemos a dominar el desarrollo para iOS, e intentemos alejarnos del método de impresión familiar y querido, y encontrar métodos más rápidos y convenientes para comprender el estado del sistema en un período determinado, comenzamos a estudiar el Área de depuración.
Lo más probable es que en el panel de depuración se te caigan los ojos antes de que entiendas exactamente qué sucede allí. Cuando la aplicación se bloquea por primera vez, el menú inferior se abre automáticamente, inicialmente puede servir como ayuda para comprender el problema (recuerde el viejo error "Error grave: índice fuera de rango"), básicamente al principio no entenderá lo que Xcode quiere de nosotros y google. errores, pero en el curso del crecimiento cada vez más información será clara.
Desde el principio, el programador está tratando de optimizar su trabajo. Para hacer esto, nos esforzamos por comprender en qué punto nuestro programa entró en un estado incorrecto. Y aquí, dependiendo del punto en el que se encuentre la evolución del programador, los métodos pueden variar. Primero, cómo se realiza la depuración correctamente mediante el método "print ()", luego se colocan los puntos de interrupción y se llaman los métodos "po", luego se familiariza con la entrada variable de depuración (el área al lado de la consola en Xcode), y luego se comprende cómo compilar el código mientras se detiene Métodos de punto de interrupción: "expresión" (al menos esa fue la evolución que tuve).
Probemos diferentes formas que nos ayudarán a comprender y cambiar el estado de nuestra aplicación. Los más simples como "print ()" y "po" no serán considerados, creo que ya entiendes su esencia y sabes cómo aplicarla.
Creemos una aplicación simple con una pantalla en la que solo tendremos un tipo de celdas (TableViewcell) con dos elementos dentro: UIImageView y UILabel. En las celdas, escribiremos su número de serie y colocaremos imagen1 o imagen2 en la imagen.
El método tableViewCellForRowAtIndexPath creará celdas para nosotros, anotará datos y devolverá:

Este método generará la siguiente tabla:

Punto de interrupción
Detengamos nuestro programa y agreguemos texto a nuestra etiqueta.
1. Establecer punto de interrupción:

2. El programa detuvo la ejecución en la línea 55, inmediatamente después de que se asignó el texto. Dado que estamos en una línea ubicada en el campo de visión de la celda, podemos interactuar con nuestra celda.
3. Escribimos en la consola un comando para cambiar el texto de la celda:

4. Eliminamos nuestro punto de interrupción y presionamos el botón "continuar la ejecución del programa".
5. En la pantalla de nuestro teléfono vemos que todo salió con éxito:

expresión ejecuta la expresión y devuelve un valor en el hilo actual.
Punto de interrupción editado
Pero, ¿qué pasa si necesitamos cambiar el texto en una gran cantidad de celdas? ¿O ya nos hemos dado cuenta en el proceso de ejecución del programa que necesitamos cambiar?
Podemos optimizar la ejecución de esta operación y acelerar un poco el trabajo, hacer que el texto cambie a celdas cuando llegue a Breakpoint y continuar ejecutando el programa, esto ahorrará mucho tiempo y nos permitirá no imprimir lo mismo para cada celda.
Para hacer esto, necesitamos modificar ligeramente nuestro Punto de interrupción, agregar un código adicional allí, que cambiará su texto en la zona de visibilidad de nuestra celda y continuará el programa.
- Crear punto de interrupción.
- Haga clic izquierdo en la flecha del punto de interrupción.
- Haga clic en Editar punto de interrupción.
- Condición: condiciones bajo las cuales funcionará Breakpoint, ahora no lo necesitamos.
- Ignorar: cuántas veces omitir Breakpoint antes de que funcione (tampoco eso).
- Pero Acción es lo que necesitamos, seleccione el tipo de acción Comando del depurador.
- Escribimos la expresión que necesitamos ejecutar:
- expresión cell.desriptionTextOutlet.text = "\ (indexPath.item) misión completa”.
- Ponga una marca: continúe la ejecución después de completar con éxito el comando.

9. Lo estamos intentando.

Esto es un éxito, resultó que cambió el texto de cada celda durante la formación de la tabla, y no tuvimos que sacrificar el tiempo y prescribir operaciones para cada una.
Función de punto de interrupción
Siempre hay momentos en los que sucede algo en nuestra aplicación que no podemos explicar, el texto no cambia o cambia más de lo necesario, parece que Breakpoint en este caso no tiene dónde ponerlo. Pero esto no es del todo cierto, si conoce Obj-C y sabe qué método ejecuta el compilador que desea rastrear, puede poner Breakpoint en él y la próxima vez que se llame al método, la aplicación se detiene en el proceso de ejecución del código Assembler.
1. En el navegador Punto de interrupción, seleccione Punto de interrupción simbólico.

2. Queremos rastrear el método de configuración del texto en la celda, escriba - [UILabel setText:].

3. El argumento cero no existe, y el conteo comienza desde el primero. El primer método detectado no es lo que necesitamos (establecemos la hora actual en la barra de estado), pero el segundo es solo el nuestro:
4. En "$ arg1" se almacena la descripción del objeto.
5. En "$ arg2" se almacena la función del selector.
6. En "$ arg3" se almacena el texto obtenido por el método.
Ok, esto parece estar claro. Pero a veces hay situaciones en las que no se limita a configurar un texto en la barra de estado, y necesita rastrear la ejecución del método en un controlador específico, ¿qué se debe hacer? Puede habilitar Breakpoint similar a lo que instalamos anteriormente, pero estableciendo su posición en el código. ¿Qué significa esto? Sabemos con certeza que nuestra vista aparecerá cuando instalemos el texto en la celda, por lo que lo más importante es ponerlo en viewDidLoad o después de crear la celda.
Para crear un punto de interrupción, lo establecemos en la línea y en la acción escribimos el siguiente código:
breakpoint set --one-shot true --name "-[UILabel setText:]”
breakpoint set —one-shot true
: crear punto de interrupción
—name
es el nombre del punto de ruptura del personaje
“-[UILabel setText:]”
llamado método
Esto es lo que sucedió:

Saltar lineas
Pero, ¿qué pasa si sospechamos que alguna línea de código estropea todo nuestro programa? Durante la ejecución del código, puede evitar ejecutar una línea de código específica como esta:
- Ponemos el punto de interrupción en una línea que no nos gustaría ejecutar.
- Cuando la ejecución se detenga, arrástrela a la línea con la que queremos continuar la ejecución del programa (curioso, pero no siempre funciona, la opción sin arrastrar es menor).
También hay otra opción que optimizará el salto de línea: esta es la prescripción del comando apropiado en el "punto de corte de edición". El equipo es arriesgado, ya que la esencia de tales saltos es salvarnos de la reconstrucción, pero si omite la inicialización del objeto e intenta contactarlo, el programa se bloqueará.

Detengamos nuestro programa al inicializar la imagen, y no asignaremos la imagen a la celda en absoluto, para esto necesitamos omitir cinco líneas de código y devolver la celda sin una imagen, para esto omitimos la ejecución de las siguientes cinco líneas de código en el hilo actual y continuamos el programa:

Suena bastante bien, pero todavía quiero asignar una imagen, agreguemos un método de asignación al punto de interrupción:

Una buena combinación, ahora solo tenemos un tipo de imagen en cada celda.
Mirador
Otra función conveniente en el depurador es el seguimiento de valores en el programa, puntos de observación. Watchpoint es algo similar a KVO, establecemos un punto de interrupción para cambiar el estado de un objeto, y cada vez que cambia su estado, el proceso de ejecución del programa se detiene, y podemos ver el valor y los lugares desde dónde y quién cambió el valor. Por ejemplo, pongo un punto de observación en una celda para averiguar qué sucede cuando se busca una tabla y se inicializa una nueva celda. La lista de comandos resultó ser muy grande, por lo que no la mencionaré solo por mencionar algunos: ejecución de la vista de diseño dentro de la celda y restricción de configuración, animación, estados de configuración para la celda y mucho, mucho más.
Para establecer el punto de observación en un valor, debe detener el programa de punto de interrupción en el alcance de las propiedades que desea monitorear, seleccione la propiedad en el panel "variable de depuración" y seleccione ver "<parámetro>".

Para eliminar el punto de observación con una variable, debe buscar en el navegador del punto de interrupción, allí junto con el resto del punto de interrupción será nuestro punto de observación.
Cambio de UI de punto de interrupción
A veces necesitamos aprender más sobre el objeto que estamos tratando de repeler. La opción más fácil es usar "po" para mostrar información sobre el objeto y observar la ubicación del objeto en la memoria en el mismo lugar. Pero sucede que no tenemos un enlace directo a un objeto; no está representado en la vista API, en la que se encuentra o posiblemente está oculto por la biblioteca. Una de las opciones es usar la Jerarquía de vistas, pero esto no siempre es conveniente y no siempre es difícil entender que ha encontrado la vista deseada. Puedes intentar usar el comando:
expression self.view.recursiveDescription()
Está en Obj-C, pero se eliminó en Swift debido a las peculiaridades del lenguaje, no podemos hacerlo, pero dado que Debuger trabaja con Obj-C, en teoría puede alimentar este comando y entenderá lo que quieres de él. . Para ejecutar el código Obj-C en la consola, debe ingresar el comando:
expression -l objc -O - - [`self.view` recursiveDescription]
Que ves aqui Veo una construcción bastante incómoda a la que uno podría acostumbrarse con el tiempo, pero es mejor que no lo hagamos, sino que use typealias para simplificar el comando:
command alias poc expression -l objc -O —
Ahora nuestro equipo se está reduciendo y simplificando, pero continúa haciendo el trabajo:
poc [`self.view` recursiveDescription]
¿Funcionará después de cerrar Xcode o en otro proyecto? Por desgracia no. ¡Pero se puede arreglar! Al crear el archivo .lldbinit e ingresar nuestro alias allí. Si no sabe cómo, aquí están las instrucciones sobre los artículos:
1. Cree un archivo .lldbinit (puede tomar .gitignore como prototipo, pertenece al mismo tipo de archivos invisibles de texto).
2. Escriba exactamente el siguiente comando en este archivo:
command alias poc expression -l objc -O - -
3. Coloque el archivo en la carpeta por la dirección "MacintoshHD / Users / <Aquí está el nombre de su usuario>".
Y así obtuvimos una descripción de todas las vistas presentadas en la pantalla. Tratemos de ver qué podemos hacer con la dirección de los objetos en la memoria. Para Swift, hay un método con un inconveniente, siempre debe convertir el tipo de objeto en la memoria a un cierto valor:
po unsafeBitCast(0x105508410, to: UIImageView.self)
Ahora podemos ver la posición de nuestra imagen en la celda, movámosla para que esté centrada en la celda y tenga una sangría en el lado de 20 px.

A veces, un cambio no se nota de inmediato, pero es necesario eliminar la aplicación de la depuración para notar el cambio.
Pero si queremos ver algo similar en cada celda, necesitamos acelerar la ejecución de los comandos, podemos escribir varios scripts en Python que nos funcionen (puede ver cómo agregar scripts aquí
www.raywenderlich.com/612-custom-lldb-commands-in- práctica ), y si sabe cómo manejar Python y quiere escribir en él para lldb, entonces será útil.
Decidí escribir una extensión para la clase UIView, que simplemente moverá la vista en la dirección correcta, me pareció que habría menos problemas para conectar nuevos scripts a LLDB y no sería difícil para ningún programador de iOS (de lo contrario, debe aprender Python para LLDB).
No busqué el lugar del objeto en la memoria y no lo llevé a la clase deseada, para poder tomar un marco más tarde, también tomaría demasiado tiempo. La pregunta se resolvió escribiendo una función en la extensión UIView:

Desafortunadamente, no funciona bien con las celdas, muy probablemente debido al hecho de que en el momento en que se ejecutó el comando de vaciado, no se calcularon todas las posiciones de las celdas y no apareció en la pantalla (todavía no hemos devuelto tableViewCell). Con otros elementos estáticos, funciona bien.
Conociendo la posición de la vista en la jerarquía, podemos acceder a ella y cambiar su posición.
Y ahora la situación inversa es cuando podemos acceder a ViewHierarchy y queremos obtener datos de vista desde allí. En Xcode, es posible ver la jerarquía de vistas durante la ejecución de un programa, también puede ver colores, diseño, tipos y enlaces a otros objetos, incluido eso. Intentemos acceder a las restricciones de nuestro UIImageView.
Para obtener datos de restricción:
1. Haga clic en la jerarquía de vista de depuración.
2. Habilite Contenido recortado en el panel en la parte inferior de la pantalla que aparece.
3. Habilite restricciones en el mismo panel.
4. Seleccione Contraint.
5. En el menú, haga clic en Editar -> Copiar (Comando + C).
6. El enlace de este tipo se copia: ((NSLayoutConstraint *) 0x2838a39d0).
7. Y ahora, tal como lo cambiamos a través del código, también puede cambiarlo en lldb:
expression [((NSLayoutConstraint *)0x2838a39d0) setConstant: 60]
8. Después de hacer clic en el botón Continuar, el elemento actualizará su posición en la pantalla.
Puede cambiar colores, texto y más de la misma manera:
expression [(UILabel *)0x102d0a260] setTextColor: UIColor.whiteColor]
El proyecto de demostración resultó ser demasiado simple (60 líneas de código en el ViewController), la mayor parte del código que escribí se presenta en el artículo, por lo que no habrá dificultades para reproducir el proyecto de prueba.
PD: Si tienes preguntas o comentarios, escribe. Echa un vistazo a WWDC y Debate como Pro.
También le aconsejo que se familiarice con los materiales:
Inspirado por Advanced Debugger WWDC 18 SessionComandos del depuradorAgregar scripts de Python a LLDB Xcode