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 2d9bfb8fba58e6ec0f2f3a18da7fbf45aaef6ba8 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?
|Solution Inside: Answer||SelectShow|
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.
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.
With all that is going on in this view, it may surprise you that there is just a single
UITableViewCell. If you look at the hierarchy in the left pane, there’s just one cell,
ARModernPartnerShowTableViewCell, which encapsulates all of the content below CURRENT SHOWS header.
UIView contains everything above, 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.
|Solution Inside: Color||SelectShow|
Good job! Without ever once touching the source code, you have a pretty good understanding of two of Artsy’s complex and beautiful screens. It looks especially sharp with all that extra real estate on the iPhone 6 Plus, doesn’t it?
Did you notice something funny a few paragraphs back? The
UILabel was 280 points wide and 40 points narrower than the cell it was inside of. That means the width of the screen is only 320 points.
The iPhone 6 Plus should have a width of 414 points, which means Artsy isn’t natively taking advantage of the larger screen.
You’ll fix the project settings so Artsy runs using the native resolution of the 6 Plus, and you’ll use Reveal to debug any layout issues that arise from the changes.
Enabling native iPhone 6 Plus resolution in projects that existed prior to the iPhone 6 Plus is a bit obscure, and you do it by specifying a Launch Screen xib in the project settings.
In Xcode, create a new Launch Screen xib by selecting File\New\File… and then choosing iOS\User Interface\Launch Screen and clicking Next. Keep the name as Launch Screen and click Create.
Next, select the Artsy project in the Project Navigator. Click the General tab and scroll down to Launch Screen File. In the dropdown, select Launch Screen.xib:
Build and run. Voila! There is quite a bit more on the screen now that the app has more pixels to play with:
Just to make sure, go back to Reveal and once again click the refresh button, then look at the width of the cell in the Layout Inspector. You’ll see it’s now
414, the full width of the iPhone 6 Plus.
You’ll also notice that overall, the app looks pretty good. Auto Layout is used extensively throughout Artsy, so although it was largely developed before the advent of the iPhone 6, the layout adapts nicely to the new size.
Of course, there are some areas that didn’t fare so well. In the Artsy app, navigate to the YOU tab:
While it’s not broken by any means, it doesn’t utilize the full width of the screen, and looks as though it’s set to use a screen width of 320 points. What an excellent place to do some live view debugging!
Live View Debugging
In Reveal, hit refresh to update the view hierarchy with the YOU screen; it should look something like this:
Right away, you see that the views containing the segmented control and the description are constrained.
Simplify your perspective by rotating the view hierarchy in the center pane 45 degrees. Then double-click on the white space to grab the visible view, and to discard the numerous nested views and navigation elements.
The view you selected should be a
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:
You’re now looking at a focused view of the YOU screen, which shows only the view boundaries and layout constraints.
To figure out how the segmented control is sized, simply click one of the segmented control buttons in Reveal and observe the participating constraints in the Layout Inspector.
Look for what’s controlling the width; you’ll see that it’s constrained to the width of the
ARSwitchView with a multiplier of
In other words, the width is a third of the containing switch view. Since that seems reasonable, it’s logical to assume the width of
ARSwitchView is hardcoded.
Confirm this by selecting
ARSwitchView – it’s one level up in the view hierarchy – and observe it’s constraints. There are quite a few, but the height and width constraints have clear labels:
The height constraint is blue so it’s added by
UIKit, but the width constraint is purple and therefore added by the developer, and is currently set to 279 points. At this point, it’s clear that this is the culprit causing the overly narrow controls.
You could assume that the design called for about 20 points of margin on each side of the control, but before diving into a heavy code-build-debug cycle, start by leveraging Reveal’s live view debugging to make sure it looks the way you intend.
Expand the width constraint in the Participating Constraints section to view its details:
Note: The priority field of the constraint is disabled because the priority of this constraint is 1000, which makes it a required constraint. If it was created with a priority less than 1000, it would be editable at runtime in Reveal.
To maintain margin parity with the previous screen size, the switch view should be 41 points narrower than the screen. Since you’re running the iPhone 6 Plus simulator, you’ll want a width of 373.
In the Constant field of the constraint, change the value from
373, and the wireframe will snap to the new size.
Now do the same for the label below, which will be a bit simpler. Click on the containing view, and find the width constraint. Then, change the constant from
364 and you’ll see that views size update again.
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!
Live debugging can greatly reduce your code-build-debug cycle, and even allows you to experiment with your design in real time.
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.