Inspecionando e alterando elementos visuais com LLDB e View Debugger

Você já colocou algum elemento em uma UIView e ele não ficou do jeito que queria? Esse post é pra você!

Gabriel Sória
Oct 13 · 8 min read
Image for post
Image for post

Alguma vez você já colocou algum elemento em uma UIView e, ao olhar no simulador, percebeu que ele não se apresentava do jeito que estava imaginando?

Bem, o nosso querido Xcode tem uma função muito útil para inspeção de elementos visuais que pode ajudar nesses casos, chamada Debug View Hierarchy, ou View Debugger. A função pode ser ativada no botão indicado abaixo, localizado no debugger do Xcode.

Image for post
Image for post

Conhecendo o View Debugger

Ao clicar nesse botão, o Xcode vai pausar a execução do seu app e capturar o estado da sua atual window.

Uma tela similar à imagem abaixo vai aparecer para você. Vamos entender um pouco do que o Xcode está nos mostrando:

Image for post
Image for post

Exploded 3D rendering of app views: vista explodida de todas as views na atual window;

View hierarchy: lista de todas as views e respectivas constraints na atual hierarquia, inclusive as referidas views que são geradas pelo próprio sistema;

View controls: controles para alterar a visualização da vista explodida da atual window, com os quais é possível observar as views em até 360 graus e também com zoom, mostrando ou escondendo views com suas respectivas constraints;

Inspector area: informações sobre qualquer objeto selecionado na vista explodida ou na hierarquia de views. A aba Object mostra informações básicas sobre a view selecionada e a aba Size mostra informações do tamanho da view e suas constraints. Inclusive é possível selecionar constraints e verificar suas propriedades.

É possível também obter algumas informações de uma view clicando com o botão direito na hierarquia ou na vista explodida. Você consegue mostrar informações do elemento no console, dar ênfase nas constraints, esconder as views que estão atrás ou na frente da view selecionada.

Image for post
Image for post

Porém, minha parte favorita é usar o view debugger junto ao LLDB e ao simulador. Você pode simplesmente ir inspecionando e alterando propriedades das views na atual hierarquia sem ter que recompilar o projeto.

Alterando propriedades de uma UIView

Execute o sample project deste link e clique no botão para ativar o view debugger.

Você vai ver a hierarquia de views abaixo. A única que importa para nós agora é a UILabel que temos na tela.

Image for post
Image for post

Caso a hierarquia de views não apareça, execute command + 7 no Xcode, clique no botão informado abaixo, e selecione a opção View UI Hierarchy.

Image for post
Image for post
Image for post
Image for post

O que vamos fazer é apenas mudar a cor de fundo desta label e ver a mudança sem ter que recompilar o projeto.

Na hierarquia de views, clique com o botão direito na UILabel e, em seguida, selecione Print Description of UILabel — View Debugger is awesome

Image for post
Image for post

Você vai ver no console que algumas informações sobre a label apareceram:

Image for post
Image for post

Está vendo esse 0x7f9c0cd07940? É o endereço de memória no qual sua label está alocada. A propósito, o endereço de memória que vai aparecer no seu console muito provavelmente é diferente do meu.

Moving on…

Copie o endereço de memória que apareceu no seu console e vamos usar um pouquinho de Objective-C no debugger (calma, Objective-C não morde):

e (void)[0x7f9c0cd07940 setBackgroundColor: [UIColor redColor]]

Bem, se olhar no view debugger e no simulador não vai ter nada de diferente (ainda), é necessário executar mais um comando para a mágica acontecer. Digite, então, o comando abaixo e veja o resultado no seu simulador.

e (void)[CATransaction flush]

🙃🙃🙃

Para ver o resultado no view debugger, você precisa clicar no botão continue abaixo (ou digitar continue no LLDB) e depois clicar no botão para chamar o view debugger de novo.

Image for post
Image for post

Vale lembrar que, ao clicar no botão de view debugger, caímos no contexto de Objective-C do LLDB, por isso não conseguimos usar Swift.

Moving on…

Ainda com o view debugger ativado, dê uma olhada nas constraints da label e faça o Xcode mostrar no console o endereço de memória da constraint de altura, bem como você fez com a label anteriormente.

Image for post
Image for post

Caso ainda tenha ficado com dúvida de como fazer, clique com o botão direito na constraint em destaque abaixo e selecione a opção Print Description

Image for post
Image for post

… ou selecione a label na vista explodida e na barra de opções de controles selecione a opção Show Constraints.

Image for post
Image for post

Veja que as constraints da label ficaram em destaque. Selecione a constraint de altura e, em seguida, clique na opção Print Description.

Copie o endereço de memória que apareceu no console e digite o seguinte comando:

e (void)[((NSLayoutConstraint *)0x6000001b0a80) setConstant: 200]

Depois atualize a view com o comando abaixo e dê uma olhada no simulador 🙃

e (void)[CATransaction flush]
Image for post
Image for post

Interessante, não?

É claro que tudo isso poderia ter sido feito colocando um breakpoint na ViewController e alterando essas mesmas propriedades, mas é sempre bom saber que elas existem. Você também pode utilizar o LLDB quando estiver com o view debugger ativado.

A maior vantagem é não precisar ter que utilizar os endereços de memória das views, e também fica mais fácil até de adicionar novos objetos no contexto atual.

Adicionando uma UIView com o LLDB

Por exemplo, coloque um breakpoint no viewDidAppear da ViewController e execute o projeto.

Digite a seguinte expressão:

e UILabel()

Diversas informações vão aparecer, mas o mais importante para nós agora é a variável que o LLDB criou, que no meu caso é $R0.

Image for post
Image for post

Vamos brincar um pouco com essa variável.

Digite as seguintes expressões:

e $R0.backgroundColor = .greene $R0.translatesAutoresizingMaskIntoConstraints = falsee self.view.addSubview($R0)e $R0.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = truee $R0.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = truee $R0.heightAnchor.constraint(equalToConstant: 200).isActive = truee $R0.widthAnchor.constraint(equalToConstant: 200).isActive = truee CATransaction.flush()

Agora é só ver o resultado no simulador!

Image for post
Image for post

Bom, é lógico que não é assim que vamos construir uma aplicação, mas é importante saber que em algumas situações não é necessário recompilar a aplicação inteira, você pode simplesmente usar o LLDB ao seu favor.

Bônus

Percebeu que o comando CATransaction.flush() foi usado algumas vezes aqui? O que acha de criarmos um alias para não precisarmos digitá-lo a todo instante?

Poderíamos muito bem ir diretamente no LLDB e escrever:

Objective-C

command alias 🚽 expression (void)[CATransaction flush]

Swift

command alias 🚽 expression CATransaction.flush()

Assim, toda vez que você executar o comando 🚽 ele na verdade executaria a o método flush da classe CATransaction.

Entretanto, ao fechar o Xcode, você teria que recriar esse alias. Mas temos uma solução para que ninguém tenha que ficar criando o alias a toda hora.

Bom, toda vez que o LLDB é invocado, ele procura por alguns arquivos de inicialização, um deles — e o mais importante para nós — é o .lldbinit.

Digite no Terminal o seguinte comando:

vim ~/.lldbinit

Caso você já tenha adicionado algo nesse arquivo, alguns comandos já estarão aí. Caso não, ele estará vazio.

Digite então:

command alias 🚽 expression CATransaction.flush()

Salve e feche o arquivo.

Caso você já esteja com o Xcode aberto, você terá que executar o comando command source ~/.lldbinit na próxima vez que invocar o LLDB. Esse comando simplesmente carrega de novo o arquivo ~/.lldbinit.

Agora na próxima vez que você tiver que executar o método flush() da classe CATransaction de novo, é só digitar 🚽 e dar enter. Bem legal, não é?

Já dá pra ter uma ideia de que o LLDB é bem poderoso e o quanto esse arquivo de inicialização pode nos ajudar. Inclusive, conseguimos até passar argumentos para alguns comandos salvos. Por exemplo, adicione o seguinte comando no seu ~/.lldbinit:

command regex — tv ‘s/(.+)/expression -l objc -O — @import QuartzCore; [%1 setHidden:!(BOOL)[%1 isHidden]]; (void)[CATransaction flush];/’

Caso você já esteja com o Xcode aberto, salve e recarregue o arquivo ~/.lldbinit .

Execute o nosso projeto de exemplo e pause no botão pause do debugger.

Image for post
Image for post

Quando o LLDB estiver disponível, digite o seguinte comando:

tv [[[UIApp keyWindow] rootViewController] view]

😇😇😇😇

Parece que tudo sumiu hehehe.

Execute o comando de novo para voltar ao normal.

Dica rápida: você não precisa digitar o comando inteiro de novo, você pode dar enter e o LLDB vai executar o último comando que você executou, ou simplesmente ir navegando entre os últimos comandos executados com as setas para cima ou para baixo do seu teclado.

Não vou entrar no mérito do que esse último comando realmente faz detalhadamente (que tal em um próximo post?), mas ficou bem claro o que podemos fazer com o LLDB para alterar alguns comportamentos sem ter que recompilar a sua aplicação e economizar um tempinho, não é?

Espero que tenham gostado! Se você quiser aprender mais e compartilhar seu conhecimento com o pessoal aqui da Concrete, é só dar uma olhada aqui e se candidatar a uma de nossas vagas. Até a próxima!

Concrete

Nós desenvolvemos produtos digitais com inovação, agilidade…

Gabriel Sória

Written by

iOS software engineer

Concrete

Concrete

Nós desenvolvemos produtos digitais com inovação, agilidade e excelentes práticas, para que o mercado brasileiro e latino-americano acompanhe a velocidade do mercado digital mundial.

Gabriel Sória

Written by

iOS software engineer

Concrete

Concrete

Nós desenvolvemos produtos digitais com inovação, agilidade e excelentes práticas, para que o mercado brasileiro e latino-americano acompanhe a velocidade do mercado digital mundial.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store