It’s also no secret that debugging user interfaces in iOS can be a pain.
While using LLDB is great for debugging code, it doesn’t really lend itself to debugging the visual hierarchy of your app.
Much like how Safari’s web inspector allows you to inspect and manipulate the DOM of a webpage, Reveal allows you to do the same with the view hierarchy of your app.
This tutorial will show you how to leverage Reveal for inspecting and debugging a complex interface, and will feature Artsy – an app made by a team of engineers that includes fellow tutorial team member Orta Therox!
First you’ll download and compile the source for Artsy from Github.
To do this, open the Terminal app, switch to the directory of your choice, and enter the following commands:
git clone https://github.com/artsy/eigen.git cd eigen git checkout 0590e315e3246b88209003885f8466af30c6dc0b bundle install make oss bundle exec pod install open Artsy.xcworkspace
Note: This is a simplified version of the instructions found in the README file for Artsy. In order to build Arsty you’ll also need the following dependencies installed:
Note: If you have trouble installing nokogiri, this should fix it (courtesy StackOverflow):
brew install libxml2 bundle config build.nokogiri "--use-system-libraries --with-xml2-include=/usr/local/opt/libxml2/include/libxml2" bundle install
The clone command will clone the Artsy repository, and checkout will point the Git repository to commit
2d9bfb8fba58e6ec0f2f3a18da7fbf45aaef6ba8 which is the commit I used at the time this tutorial was written, so there are no discrepancies between the latest version and the version I used to write this.
Once Artsy opens in Xcode, select the iPhone 6 Plus simulator and then build and run to verify everything works. You’ll see this splash screen:
Continue to use the iPhone 6 Plus simulator for the remainder of the tutorial as it’s provides the biggest screen and is therefore perfect for view debugging.
Next, you’ll learn how to connect Artsy to Reveal for view debugging.
Head over to the Reveal download page and click Download Trial to grab the trial version of Reveal – or if you’re already sold on the idea at this point then go ahead and click Buy Now at the top-right side of the page. :]
Unzip the downloaded archive and then drag Reveal.app into your Applications folder.
Now open Reveal – a quick and easy way is to trigger Finder by pressing ⌘+space and typing in “Reveal” – and you’ll see a first-launch splash screen. If you’d like, take some of the guided tours — don’t worry, we’ll wait for you.
After dismissing the splash screen, you’ll see Reveal’s main interface. At the moment it’s empty:
You’ll remedy that in a moment when you integrate Reveal into the Artsy app.
In a nutshell, Reveal needs to run some code in your app so it’s able to communicate with it via Bonjour. There are a few options for adding the Reveal framework to your app:
- By statically linking the framework into your executable using Reveal.framework — this is the easiest and most common way to do this.
- By dynamically linking the framework into the app at runtime using libReveal.dylib — this can give you more control over when the library loads into your application.
- Using CocoaPods to import Reveal as a dependency.
For this tutorial, you’ll statically link the framework since it’s the most efficient approach. For detailed instructions on how to use the other methods, head on over to Reveal’s integration page.
- Make sure Reveal is the selected window and navigate to Help\Show Reveal Library in Finder. A Finder window will appear showing both the static library named Reveal.framework and the dynamic library named libReveal.dylib:
- Drag Reveal.framework into the Frameworks group in the Project Navigator in Xcode. Check Copy items if needed, and check the Artsy target. Finally click Finish:
- Select the Artsy project in the Project Navigator, then go to Build Phases\Link Binary with Libraries, and add libz.dylib by clicking the + in the lower-left corner. Enter libz into the search box, and then select libz.dylib and click Add:
- Delete the app from the simulator, then build and run. When it’s running you should see Artsy (iPhone Simulator) in the connection dropdown in the top-left of the Reveal app:
At this point, everything is ready for you to start debugging the view heirarchy.
In the connection dropdown, select Artsy (iPhone Simulator). The Reveal app will finally light up!
You’re currently looking at a layered view of Artsy’s current view hierarchy. It’s important to emphasize current because any changes to the app’s view hierarchy outside of Reveal won’t be reflected until you refresh the hierarchy.
To see this in action, tap the SIGN UP button in Artsy. You’ll see the app navigate to the sign up view, but Reveal still shows the original splash screen.
To remedy this, click the refresh button in the top-right corner of the Reveal app, and voila, the view hierarchy updates to show new sign up view.
Tap the back button to return to the splash screen, and click Refresh again in Reveal. You’ll become very familiar with this navigate/refresh/debug cycle as you learn how to use Reveal.
A Quick Tour of Reveal
Next let’s take a quick tour of Reveal, looking in detail at the three panes that make up the window — the center pane, the left pane and the right pane.
The Center Pane
The center pane is the layered view of the current view hierarchy. Click+Drag anywhere in the center pane, and you’ll see the view hierarchy rotate in 3D. You’ll also notice Reveal adds a bit of space between each layer to help you visualize the view-subview relationships:
On the top of the center pane, you’ll also see 3 controls:
- A segmented control with three icons that look like picture frames. From left to right, these show View Wireframes, View Contents and View Both. A view’s wireframe is just a thin border around a view, and it’s useful when you want to understand how a view is positioned on the screen.
- A dropdown that shows the size of the view hierarchy’s future render; note that it’s relative to the native size.
- Another segmented control that switches between 2D and 3D perspectives. 3D is the default, and what allowed you to rotate the view heirarchy a few moments ago.
The Left Pane
The left pane shows the view hierarchy, where each entry is labelled by it’s subclass. Scan up and down and you’ll see a mix of instances of
UIView and instances of private UIKit view subclasses:
Scroll to the top, and you’ll see the root of the entire hierarchy is an instance of
UIScreen, which you can then trace down to any child view. Back in the center pane, tap the SIGN UP button on the splash screen to select it.
You’ll see the corresponding
ARWhiteFlatButton is also selected in the left pane — this also works the other way around. Now find where that button lies by traversing up the heirarchy until you get back to the root
A few purple lines appeared when you tapped the SIGN UP button in the center pane. This is a new feature introduced in Reveal 1.5 that lets you visualize Auto Layout constraints. You’ll find out more about how those work shortly.
The Right Pane
The right pane is what you’ll use to edit or debug the view hierarchy, and the organization is similar to Interface Builder’s inspector panes:
The right pane has five tabs:
- Application Inspector: This provides application-wide information such as the device you’re connected to, the OS version, and even the current orientation!
- Identity Inspector: This shows the object of the node you select, such as class, memory location and accessibility information. One useful tool you’ll find here is View Controller, which displays the view controller that owns the selected view, provided it’s the root view within that view controller.
Attributes Inspector: This shows some of the public properties for every class in that object’s class hierarchy, much like Interface Builder. If it’s a
UILabel, for example, the top section will have attributes such as Text and Font. Further down — which ironically is actually moving up in the class hierarchy — you’ll see a section for
UIResponderwhere you can see if the view is currently the first responder.
- Layout Inspector: This is where you’ll see the frame, bounds, auto-resizing mask and Auto lLayout characteristics, such as content hugging values and intrinsic content size.
Layer Inspector: Like the name implies, this is where you access the view’s
CALayer. Here you can view and edit the layer’s border, corner radius, and even if the layer should rasterize it’s contents.
Viewing Layout Constraints
Select the SIGN UP button by tapping it in the center pane. Next, expand the node of the corresponding
ARWhiteFlatButton in the left pane to view its children.
You’ll find a Constraints node, along with the rest of the view hierarchy, that contains the layout constraints belonging to that view. If you expand it, you’ll see the button has two constraints that pin it’s width to 280 points and it’s height to 44 points:
In the right pane, open the Layout Inspector – the fourth tab – and scroll to the bottom until you see the Participating Constraints section, which contains the same two constraints that belong to the LOG IN button, as well as two others that dictate the position of the
You may notice that the two size constraints are blue, and the other two constraints are purple.
- Blue: Represents constraints generated automatically
- Purple: Represents constraints added manually by the developer
In this case, blue represents the intrinsic content size of the button, which is why the system automatically created these constraints.
The purple constraints are created by the developer, and are related to the positioning of the label inside the button.
Inspecting Artsy’s Splash Screen
While a brief tour of Reveal is great for getting started, using it to debug a running app will really reveal the true value of this tool.
One of the best uses of Reveal is to help a developer understand the structure of an app’s interface. Since it’s likely you’re not overly familiar with Artsy, it’s a great example to demonstrate this.
Make sure Reveal is showing the Artsy splash screen, and providing you’ve not gone ahead and signed up, you’ll still see the the options to sign up or proceed without an account.
Select the 3D option at the top of the center pane, and make sure the zoom level is set so you can see the entire view hierarchy:
First, you need to find out what view controller is responsible for the current view.
Activate the Identity Inspector in the right pane – the second tab – and click somewhere in the background view of the splash screen. In the left pane, you’ll see this view is now highlighted in the hierarchy:
In the right pane, you’ll see the Identity Inspector populate with the selected view’s details. More importantly, toward the bottom of the pane, the View Controller field is populated with the name of the splash screen’s view controller:
Note: The view you select when you click in the center pane will be the topmost view under your mouse pointer. This is, of course, not necessarily the root of a view controller; for example, it could be a background image that covers the view. Sometimes, you need to traverse up the hierarchy in the left pane to find the root view, and thus the corresponding view controller.
In the center pane, there are some images peeking out of the bottom of the hierarchy that aren’t visible when looking at the app. Get a better look by clicking and dragging to the left in the center pane until the views are rotated about 45 degrees:
Interesting. There’s quite a bit hiding beneath the covers! What you see is an entire view already rendered underneath the splash screen. So, what’s going on here?
The displayed hierarchy is a bit messy to behold with so many layers. It would be much easier to see what’s going on by flattening the splash screen to isolate what presents itself on screen as opposed to what lurks beneath.
To flatten, go to the left pane, locate the view for
ARSignUpSplashTextViewController and traverse up the hierarchy. As you move up, collapse the views below by clicking the disclosure triangle to the left of each node:
Every time you collapse a node in the left pane, you’ll see the corresponding layers and borders around each layer merge in the center pane, making it a bit easier on the eyes. Continue to do this until you’ve collapsed everything up to
UILayoutContainerView, go back to the Identity Inspector tab in the right pane, and you’ll see the view controller
AROnboardingViewController that appears to manage the splash screen and the rest of the startup experience, including the login screen you visited briefly earlier.
As it turns out, the splash screen is presented over some hidden content. Drill down into it to learn how the splash screen is presented with this stunningly low-tech approach. :]
In Xcode, open the Find in Workspace search box by pressing ⇧ + ⌘ + F and search for AROnboardingViewController to find where it’s presented from.
In the search results, look for the instance where it’s created in ARAppDelegate.m. Click on that result and Xcode will navigate to it.
You’ll find the following four lines that create and present the instance of
AROnboardingViewController *onboardVC = [[AROnboardingViewController alloc] initWithState:state]; onboardVC.trialContext = context; onboardVC.modalPresentationStyle = UIModalPresentationOverFullScreen; [self.viewController presentViewController:onboardVC animated:NO completion:nil];
AROnboardingViewController is actually presented by another view controller, but the interesting twist is the
modalPresentationStyle is set to
This presentation mode was introduced in iOS 8, and the
UIModalPresentationStyle documentation reads:
A presentation style where the content is displayed over only the parent view controller’s content. The views beneath the presented content are not removed from the view hierarchy when the presentation finishes. So, if the presented view controller doesn’t fill the screen with opaque content, the underlying content shows through.
Ah, so by using this presentation mode both the presenting view controller’s view heirarchy and the presented view controllers view heirarchy are drawn on screen. Good to know!
Challenge: Changing Modal Styles
Though you may have known about these new modal presentation styles in iOS 8, have you been able to play around with them? Reveal actually helps you visualize the effect you get from using
Challenge: Change the
UIModalPresentationFullScreen. How can you use Reveal to tell the difference between the two presentation styles?
After you change the presentation style, build and run the app and reconnect the simulator in Reveal. You may need to delete the app from the simulator first.
All the off-screen content that wasn’t drawn in the simulator but showed in Reveal is now removed from the view hierarchy. As the content is no longer in the view hierarchy, Reveal doesn’t display it:
Inspecting Artsy’s Home Screen
You’ve paid enough attention to the splash screen, so it’s time to move on to the home screen.
If you haven’t already, dismiss the splash screen by tapping TRY WITHOUT AN ACCOUNT. The splash screen will dismiss and you’ll see the home screen that you previously saw lurking underneath the splash screen:
Take a moment to play around with the contents of the home screen. It’s fairly rich in content, with some artwork in the header and a plethora of controls in the white area below. If you scroll up, you’ll even see the white content scroll over the artwork.
There is clearly quite a bit going on here, but how is it built? Now that you have Reveal at your side, dissecting the view hierarchy will be no problem.
“Revealing” the Home Screen
Back in Reveal, hit the refresh button to update the view hierarchy. You should see Reveal look something like this:
A couple of things that you’ll notice immediately:
- The artwork at the top appears to sit below the content area.
- The content area appears to be a
UITableView, based on the numerous vertically stacked views, but is still too complex to understand from this vantage point.
It’s a good idea to dive into the table view to get a better idea of its construction.
In Reveal, focus on the table view by rotating the view 45 degrees to the right and clicking on the area below all the content and cells, which will select the instance of
Now that you’ve selected the table view, it’s fairly obvious how to achieve the effect where the table view appears to scroll over the content below.
The content view is not part of the table view, but the table view is on top of the content view. The content view is visible because the table view is allowed to scroll down far enough to show it!
With the table view selected, open the Attributes Inspector in the right pane. Scroll down to the
UIScrollView section, and you’ll see the
Y value of the content offset is
-252, which moves the content down far enough to see the content behind it.
Y value to
0, and then watch the content section snap to the top and cover the artwork behind it.
“Revealing” the Table View
Double-click on the table view in the view hierarchy you just selected. Alternatively, double-click on
ARTopTabThroughTableView in the left pane. You’ll see Reveal now focuses on the table view and the rest of the view hierarchy is no longer shown:
Focusing on a particular view in the hierarchy makes it easier to concentrate on that one area, as well as being easier to navigate. The view hierarchy in the left pane is also much simpler now.
Note: You can return to the full view hierarchy by clicking the back button at the top-left of the Reveal window, or by using the breadcrumb trail that’s along the top.
If you look at the hierarchy in the left pane, you’ll see that the cells begin under the CURRENT SHOWS header, and are of type
UIView contains everything above the cells, and you achieve this by setting a custom
tableHeaderView on the table view.
One more observation to makes is that all the cell’s contents don’t reside in it’s
contentView, but instead are placed directly inside it’s
Dive one level deeper by double-clicking on
ARModernPartnerShowTableViewCell in the left pane to focus on the cells construction:
From this perspective, it’s easy to see how the break down of the heirarchy. There are three separate instances of
UILabel that display information about the collection, and a
UICollectionView wrapped inside a
UIView, which displays a collection of artwork.
There are many methods that you can use to center labels with Auto Layout, but which one did the Artsy engineers use?
Click on the top label and view the Participating Constraints section of the Layout Inspector to see how it’s done:
Reveal reveals (sorry!) the layout is achieved by pinning the label to the center of its superview, combined with making the width 40 points less than the superview to provide padding.
Two additional constraints seem a bit out of place. Look at the most recent screenshot; there’s one constraint limiting the width to 167.66 and one keeping the height at 19.33. Look at the top of the Layout Inspector tab, and you’ll see that the label’s actual width and height is 280 x 19.333.
What’s happened with these constraints, and where did they come from?
In this case, the width and height in blue represent the intrinsic content size of the label, or in other words, the measured size of the text within the
UILabel. Since these are system constraints, they are discarded when laying out the label in favor of those constraints added by the developer.
If you want a reminder of what the colors mean, expand this spoiler.
[spoiler title=Color Explanation]
- Blue: Represents constraints generated automatically
- Purple: Represents constraints added manually by the developer
Good job! Without ever once touching the source code, you have a pretty good understanding of two of Artsy’s complex and beautiful screens.
Live View Debugging
In Artsy, hit the EXPLORE button the tab bar. Then in Reveal, hit refresh to update the view hierarchy with the EXPLORE screen; it should look something like this:
Imagine you would like to experiment with the visuals a bit, such as the background color and the text content.
In Reveal, click on the white background behind the cells to select the background view.
Open the Attributes Inspector in the right pane. Scroll down to the
UIView section where you will find the Color group.
Select the dropdown for
background and choose Light Gray Color, the background color should update in Reveal:
The new background looks pretty good, but darkening background reduced some of the contrast between the image and the background.
In the center pane, click on one of the images to select it. It will likely grab the
UIImageView itself, though you will want to select the
UICollectionViewCell subclass it is a part of instead. In the left pane, select the
ARBrowseViewCell that the
UIImageView is a subclass of.
Open the Layer Inspector in the right pane. Scroll down to the Border section and change the
width to 1, and the
color to Dark Gray Color:
Note: Changes to the layer’s border generally won’t be visible unless the view hierarchy is “collapsed” in Reveal.
The center cell now has a 1-point border to help give the images some pop from the darker background.
Not only did you just change
UIView properties in real-time, but you also were able to modify the
CALayer itself. Pretty powerful stuff.
Select the “AUCTIONS” text in the middle cell. Then, open the Attributes Inspector in the right pane and change the
text field to:
Ray Wenderlich Art Fair - Come browse hundreds of the finest collection of Rageface art from around the world!
In the same inspector, change the
lines property to 0 to support word wrapping:
You should see the updated text show up in Reveal:
Live Debugging Constraints
The text is now more of a paragraph than a title, so you should try making it a bit more flush against the sides of the cell by modifying the constraints.
Oftentimes it’s easier to debug constraints in Wireframe Mode, which shows just the view’s boundaries and the layout constraints. So, at the top of the center pane, press the left-most button on the left segmented control. Then rotate the view back so you’re looking at it from the front:
Open the Layout Inspector and scroll down to the Participating Constraints section. You will see 3 app constraints:
- width: superview.width – 26
- leading edge: superview.leading + 13
- bottom edge: superview.bottom + 13
The numbers -26, +13, and +13 represent the
constant values of each constraint.
Expand each constraint, and change the
constant values to 0 to snap the label to the bottom, left, and right edges of the cell.
Go back to the simulator and check out the app now. You’ll see all the views are updated – yes, this is all in real time – and observe the effect of the new constraints you added without touching a single line of code!
Where To Go From Here?
Well, this tutorial is done, and you should reward yourself for working through it! Try plugging one of your colleague’s apps into Reveal and see what you can find.
I bet you find a few holes here and there, and can even find ways to improve it with the powerful real-time view debugging. Then share what you find and get your colleague to buy you a beer or few in exchange for your valuable insight.
To view a thorough list of all the features Reveal supports, check out their Features page.
Also, have a look at the Release Notes for Reveal 1.5 to get more detailed descriptions of all the new features.
Finally, I recommend you check out this video of Sean Woodhouse from Itty Bitty Apps giving a live demo of Reveal in action.
I’d love to hear your take on Reveal 1.5, what you’ve learned as you’ve explored it, and of course, any questions that arose as you worked through this tutorial. Please leave your notes, brags, discoveries and questions below so that we can all learn together.