Integrating Reveal without modifying your Xcode project
So you use Reveal and you love it. But you’ve just fired up a new app in Xcode’s debugger and you want to have a quick look at the internals of the app’s view hierarchy, but you haven’t integrated Reveal via the static or dynamic library yet. What to do?
No problem! LLDB to the rescue.
LLDB can execute arbitrary code inside your running application. So you can just load Reveal into any iOS process you are currently debugging.
Just hit ^⌘Y to pause the iOS app in the Xcode debugger and then at the
(lldb) prompt type:
expr (void*)dlopen("/Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/libReveal.dylib", 0x2); expr [(NSNotificationCenter*)[NSNotificationCenter defaultCenter] postNotificationName:@"IBARevealRequestStart" object:nil]; continue
OK, so maybe not so simple and easy to remember. Wouldn’t it be better if we could just
reveal_load at the LLDB prompt or something like that?
Well, we can! LLDB supports command aliases. Just like with bash, you can create an alias
in LLDB for a more complex command. The syntax is a bit different but the concept is the
same. Also, just like bash, LLDB has a ‘dot file’ that it loads every time it starts
which is the ideal place to put your LLDB command alises. That dot file is
Open up your favourite text editor, create the file
.lldbinit file in your home
directory and chuck the following LLDB command aliases into it:
command alias reveal_load_sim expr (void*)dlopen("/Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/libReveal.dylib", 0x2); command alias reveal_load_dev expr (void*)dlopen([(NSString*)[(NSBundle*)[NSBundle mainBundle] pathForResource:@"libReveal" ofType:@"dylib"] cStringUsingEncoding:0x4], 0x2); command alias reveal_start expr (void)[(NSNotificationCenter*)[NSNotificationCenter defaultCenter] postNotificationName:@"IBARevealRequestStart" object:nil]; command alias reveal_stop expr (void)[(NSNotificationCenter*)[NSNotificationCenter defaultCenter] postNotificationName:@"IBARevealRequestStop" object:nil];
The above snippet creates four command aliases:
reveal_load_sim- This alias only works when running your app on the iOS Simulator. It loads the
libReveal.dylibfrom the Reveal application bundle (assuming you put Reveal in your system’s Applications folder). If you have Reveal elsewhere change the alias to reflect this.
reveal_load_dev- This alias works when running your app on device or in the iOS Simulator. It however assumes you have added the
libReveal.dylibbundled with Reveal to your application’s Copy Resources build phase. (Make sure it is not in your Link Binary with Libraries build phase. Yes, I was fibbing a little about not having to modify your Xcode project. Sorry.
reveal_start- This alias posts a notification via NSNotificationCenter to start the Reveal server.
reveal_stop- This alias posts a notification via NSNotificationCenter to stop the Reveal server.
Note: *Invoking the
reveal_start command is only required if you invoke one of the
reveal_load commands after iOS has posted the
UIApplicationDidFinishLaunchingNotification notification. i.e. After your application delegate has handled
With these aliases defined you can now issue these quick commands at the LLDB prompt in Xcode. LLDB even auto-completes them for you!
Ok so now you have some quick LLDB command aliases and can trigger them manually, how do you make it more automatic?
Xcode (LLDB really) can execute commands in response to breakpoints. Using this knowledge we can add breakpoints to our application that load and start Reveal automatically.
The image above shows how you can add the Reveal LLDB commands to a break point in Xcode.
Some things to note about this breakpoint:
- The break point is set to continue automatically so that the debugger doesn’t stop your app from executing when it loads Reveal.
- Both the load and start commands are being executed. If you place your breakpoint in
application:didFinishLaunchingWithOptions:you don’t have to actually issue the
reveal_startcommand. Reveal automatically listens for
UIApplicationDidFinishLaunchingNotificationand starts automatically when this notification is fired by an app. There is no harm in trying to start Reveal twice. You might just see duplicate log messages.
When the breakpoint commands are successfully executed by LLDB you will see something like the following in the debugger console:
(void *) $0 = 0x0000000109022350 2013-11-07 15:18:20.687 Test[18049:70b] INFO: Reveal server started.
Now you’re armed with LLDB and Reveal super powers!