Addresses Revealed

I’m not a fan of the development cycle on iOS. The delays caused by recompilation and app launch are so frustrating that I try go through this tedious process as rarely as possible. Obviously, I still have to get some work done, so lately I’ve found myself using two tools indispensable in the course of making my life easier. I use both LLDB and Reveal to call arbitrary methods at runtime.

Calling a method requires having access to the target, usually in the form of an address representing the memory location of an object. This begs the question: how can we easily obtain an address when the application is running?

Getting the Address

Getting the memory location of an object is as easy as placing a breakpoint and getting the value straight from the variables preview. That approach, however, is not very convenient. Being forced to stop the execution of our program just to fetch the address is way too much hassle.

To get rid of the laborious “pause on breakpoint – read value – continue” cycle we could pollute the code with calls to NSLog:

NSLog(@"Address is %p", object);

Fortunately, there is a cleaner way. We can edit the breakpoint workflow by adding a print action and forcing a breakpoint to “Automatically continue after evaluating”:

This doesn’t solve the issue completely. What if I want to get the address of a specific UITableViewCell? Putting a breakpoint in - (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath; would trigger the breakpoint multiple times, once for each cell. Granted, we could modify the breakpoint condition as well, ensuring that the cell’s address gets printed only for a specific NSIndexPath, but that’s already overkill for getting the value of a single memory location. Moreover, the breakpoint method won’t work for UIKit classes, where we don’t have straightforward access to the object’s properties and ivars anyway.

This is where Reveal comes into play. Having the visual representation of the view hierarchy mapped to the underlying objects is extremely useful. The killer feature for me is the fact that the Itty Bitty Apps kindly shared with us the address of the inspected view:

Making Use of the Address

What can we use an object’s address for? Direct execution of arbitrary methods, for one. By pausing the app and typing one-line commands into LLDB you can literally call whatever method you want.

Public Methods

The most useful methods to call are public methods. Modifying an object at runtime, without writing any code, is surely a useful capability to have:

Request layout

e [(UIView *)address setNeedsLayout];

Change the value of a custom property inside the UIView subclass

e [(ChartView *)address setLineStrokeColor:[UIColor redColor]];

Reload that pesky UICollectionView

e [(UICollectionView *)address reloadData];

Private Methods

I’m a huge fan of iOS Runtime Headers. Peeking into the list of methods a given class implements is eye-opening and makes rapid prototyping much easier. While the referenced repo is the definite guide on hackery, the following two methods make coding much more flexible:

Get quick access to the nearest UIViewController for a given view

po (UIViewController *)[(UIView *)address _viewControllerForAncestor];

Does this control have any targets?

e (BOOL)[(UIControl *)address hasOneOrMoreTargets];

A Quick Summary

While this method works great for the visual side of your application, Reveal won’t help you get the addresses of your model objects, so in this case you’ll probably have to use breakpoints or logging.

For the UI work, the LLDB-Reveal combo is a great tool that makes rapid iteration much more pleasant.

Code Pilot - 7 days later
The Story of Code Pilot