[null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-reveal-discovery-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-reveal-discovery-1.jpg", "formatted_filename": "figure reveal discovery", "alt_text": "Debugging Applications With Reveal"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-reveal-user-interface-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-reveal-user-interface-1.jpg", "formatted_filename": "figure reveal user interface", "alt_text": "Reveal's Beautiful and Focused User Interface"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-reveal-view-hierarchy-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-reveal-view-hierarchy-1.jpg", "formatted_filename": "figure reveal view hierarchy", "alt_text": "View Hierarchy"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-search-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-search-1.jpg", "formatted_filename": "figure search", "alt_text": "Reveal's Powerful Search Capabilities"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-search-2.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-search-2.jpg", "formatted_filename": "figure search", "alt_text": "Reveal's Powerful Search Capabilities"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-search-3.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-search-3.jpg", "formatted_filename": "figure search", "alt_text": "Reveal's Powerful Search Capabilities"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-reveal-user-interface-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-reveal-user-interface-1.jpg", "formatted_filename": "figure reveal user interface", "alt_text": "Reveal's Main Window or Canvas"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-1.jpg", "formatted_filename": "figure canvas", "alt_text": "Frames, Contents, or Both Frames and Contents"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-2.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-2.jpg", "formatted_filename": "figure canvas", "alt_text": "You can switch between a two-dimensional and a three-dimensional rendering of your application's view hierarchy."}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-3.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-3.jpg", "formatted_filename": "figure canvas", "alt_text": "The three buttons on the right of the search bar allow you to control what's being rendered by Reveal."}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-4.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-4.jpg", "formatted_filename": "figure canvas", "alt_text": "The middle button shows or hides system views."}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-5.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-canvas-5.jpg", "formatted_filename": "figure canvas", "alt_text": "The slider in the bottom right allows you to zoom in and out."}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-focus-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-focus-1.jpg", "formatted_filename": "figure focus", "alt_text": "You can focus on a view or collection of views by double-clicking a view in the canvas or the view hierarchy on the left."}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-collapsing-views-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-collapsing-views-1.jpg", "formatted_filename": "figure collapsing views", "alt_text": "Another option is collapsing the view hierarchy on the left."}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-jump-bar-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-jump-bar-1.jpg", "formatted_filename": "figure jump bar", "alt_text": "You can use the jump bar in Reveal to step through the view hierarchy."}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-application-inspector-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-application-inspector-1.jpg", "formatted_filename": "figure application inspector", "alt_text": "Application Inspector"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-identity-inspector-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-identity-inspector-1.jpg", "formatted_filename": "figure identity inspector", "alt_text": "Identity Inspector"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-attributes-inspector-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-attributes-inspector-1.jpg", "formatted_filename": "figure attributes inspector", "alt_text": "Attributes Inspector"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-layout-inspector-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-layout-inspector-1.jpg", "formatted_filename": "figure layout inspector", "alt_text": "Layout Inspector"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-ambiguous-layout-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-ambiguous-layout-1.jpg", "formatted_filename": "figure ambiguous layout", "alt_text": "Ambiguous Layout"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-ambiguous-layout-2.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-ambiguous-layout-2.jpg", "formatted_filename": "figure ambiguous layout", "alt_text": "Ambiguous Layout"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-layer-inspector-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-layer-inspector-1.jpg", "formatted_filename": "figure layer inspector", "alt_text": "Layer Inspector"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-view-debugger-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-view-debugger-1.jpg", "formatted_filename": "figure view debugger", "alt_text": "Unable to Capture View Hierarchy"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-refresh-snapshot-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-refresh-snapshot-1.jpg", "formatted_filename": "figure refresh snapshot", "alt_text": "Refresh Snapshot"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-unsatisfiable-layout-1.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-unsatisfiable-layout-1.jpg", "formatted_filename": "figure unsatisfiable layout", "alt_text": "Unsatisfiable Layout"}, null, {"document_url": "https://cocoacasts.com/debugging-applications-with-reveal", "unformatted_src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-unsatisfiable-layout-2.jpg", "src": "https://cocoacasts.s3.amazonaws.com/debugging-applications-with-reveal/images/figure-unsatisfiable-layout-2.jpg", "formatted_filename": "figure unsatisfiable layout", "alt_text": "Unsatisfiable Layout"}, null]
Debugging Applications With Reveal

by Bart Jacobs | Apr 17, 2018 | Tools



In Debugging Applications With Xcode, we explored Xcode's built-in view debugger. While I occasionally use Xcode's view debugger to debug user interface issues, I mostly use Reveal, a third party application developed and maintained by Itty Bitty Apps. In this episode, I show you how Reveal compares to Xcode's built-in view debugger and why I prefer Reveal over Xcode to debug user interface issues.

Before we start, I need to mention that Reveal is a paid application. This episode isn't sponsored by Itty Bitty Apps and I don't receive a kickback if you purchase Reveal. Reveal is a fantastic application that you need to know about. It's as simple as that. The application is under active development and Itty Bitty Apps releases bug fixes and new features on a regular basis. You can try Reveal for free by visiting its website.

Integrating Reveal

Let's start with Reveal's most important drawback. Apple's view debugger is built into Xcode and that means you can fire up the view debugger with a single click. That isn't true for Reveal. To inspect an application with Reveal, you need to link the application with the Reveal Server framework. That's very easy to do, though, and Reveal offers several options.

I almost always use CocoaPods. It's the simplest solution if you use CocoaPods as your dependency manager. You can also manually link the Reveal Server framework into your application if you don't use CocoaPods. Another option is loading the Reveal Server framework via a breakpoint in Xcode. This option is interesting if you don't want to modify your project. Each of these options is covered in detail in Reveal's integration guide.

Let me show you how easy it is to integrate Reveal using CocoaPods. Install Reveal and download the starter project of this episode if you'd like to follow along. I'm going to show you how to integrate Reveal into Cloudy, a simple weather application that uses CocoaPods to manage its dependencies.

Open the project's Podfile and add Reveal as a dependency of the Cloudy target.

It's important that you only link your application with the Reveal Server framework in development. CocoaPods makes this easy. Dependencies are by default linked into builds of your application for every configuration of the target. We can override this behavior by specifying which configurations a dependency needs to be enabled for. For Reveal, we specify in the project's Podfile that it should only be linked into builds of your application that are compiled using the Debug configuration.

Run the pod install command to install the dependencies specified in the Podfile.

That's it. Open Cloudy.xcworkspace in Xcode and run the application to make sure we successfully integrated Reveal into Cloudy. Open Xcode's console and inspect the output. Reveal Server logged a message to the console, indicating that we can inspect the application using Reveal.

It's time to launch Reveal. Reveal automatically detects and lists the applications it can inspect. Every application running Reveal Server can be inspected if it runs in the simulator or, if you've deployed your application to a device, if it's accessible over Wi-Fi or USB. Because I'm running Cloudy on a device connected over USB, Reveal gives me the option to connect over Wi-Fi or USB. Connecting over USB is fast and convenient if your development machine or your device isn't connected to a Wi-Fi network.

Exploring Reveal

The first thing you see is Reveal's beautiful, focused user interface. It sports a dark look that feels familiar if you've worked with Xcode's view debugger. Let's take a closer look at Reveal's user interface. View Hierarchy

As in Xcode's view debugger, the view hierarchy of your application is visible on the left. Reveal shows you only what's useful and it makes clever use of icons, colors, and transparency. Views that are hidden or not visible are slightly dimmed. Each UIKit component has its own icon in the view hierarchy on the left, which makes navigating the view hierarchy fast and more efficient. Finding a user interface element is quick and easy with the search bar at the bottom. Like Xcode's view debugger, Reveal's search bar is smart. Enter a few characters and chances are that Reveal shows you what you're looking for. You can even search for the text of a label or the title of a button. You can also specify what your query needs to match, such as class name, accessibility label, or view tag. You can even search for a memory address. What I like most is how the search results are presented to the user. The search results are visible in the view hierarchy, but they're also highlighted in the canvas. Reveal includes neighboring views to provide more context. Reveal's canvas is a gorgeous display of what a dedicated development tool can look like. It shows a beautiful three-dimensional view of your application's view hierarchy. Reveal gives you a few options to control what's visible in the canvas. As in Xcode's view debugger, you can ask Reveal to only display the frames of the views in the view hierarchy, their contents, or both frames and contents. The latter is what you'll find yourself using most often. Only showing frames is useful if you're inspecting the constraints of a view or if you're debugging Auto Layout issues. You can switch between a two-dimensional and a three-dimensional rendering of your application's view hierarchy. Even though the three-dimensional view looks appealing, remember from Debugging Applications With Xcode that the two-dimensional view has its benefits. For example, the two-dimensional view is very convenient if you need to inspect the alignment of several views. The three buttons on the right of the search bar allow you to control what's being rendered by Reveal. You can show or hide constraints and layout guides in the view hierarchy on the left by toggling the first button. The middle button shows or hides system views. If you enable this option, the status bar appears at the top. Notice that the status bar lives in its own window. That's why it's always laid on top of your application's view hierarchy. The button on the right shows or hides hidden views. Remember from Debugging Applications With Xcode that this option comes in handy to debug user interface issues.

The slider in the bottom right allows you to zoom in and out. This is useful, but it's faster and more convenient to scroll and press the Command key. The button on the right of the slider resets the canvas. Like Xcode's built-in view debugger, you can focus on a view or collection of views by double-clicking a view in the canvas or the view hierarchy on the left. Notice that Reveal animates the transition. This may seem like a gimmick, but it really isn't. When you're working in a complex view hierarchy, these subtle visual cues add context and they're incredibly helpful.

Focusing on one or more views is one option to remove clutter. Another option is collapsing the view hierarchy on the left. Reveal flattens collapsed views in the three-dimensional view to help you focus on what matters. The jump bar at the top of the window behaves slightly differently from the jump bar in Xcode's view debugger. You can use the jump bar in Reveal to step through the view hierarchy, changing the scope of the focus. Last but not least, the focus history buttons on the left of the jump bar allow you to traverse your focus history. They're similar to the Go Back and Go Forward buttons in Xcode.


Application Inspector

Reveal includes a range of inspectors on the right. The first inspector, the Application Inspector, displays information about the application, such as its identifier for vendor, the name and model of the device, and the version of the operating system. You can obtain this information through Apple's SDKs, but having this information at your fingertips is convenient at times.

Identity Inspector

Reveal populates the Identity Inspector the moment you select a view in the view hierarchy or the canvas. It shows a bunch of properties that are related to the current selection, such as the view controller that manages the selected view, its class, and memory address. As a (freelance) developer, you occasionally need to work on projects you're not familiar with. Reveal has helped me countless times with this sometimes daunting task. Reveal makes it easy to figure out which view controller a view belongs to. It's a fast and efficient technique to browse a codebase you're not familiar with.

I have to admit that I miss the view controller banners Xcode displays in the view debugger. I hope that feature makes it into Reveal some day.

Attributes Inspector

Reveal's Attributes Inspector is one of the features that sets it apart from Xcode's view debugger. The view debugger built into Xcode shows you some of the attributes of the currently selected element. Reveal takes it a few steps further. It lists more attributes and, more importantly, most of them are editable. This is only possible because Reveal doesn't interrupt the execution of your application. Remember that Xcode pauses the execution of your application to capture a snapshot of your application's view hierarchy. Any change you make in Reveal is reflected in the canvas as well as on the device or in the simulator.

Layout Inspector

The Layout Inspector summarizes the layout properties of the currently selected view, including its frame, bounds, and constraints. Most of the attributes are editable, which means you can make live changes to the layout properties of the currently selected view. This is very powerful. Let me show you what I mean. Switch to Reveal's two-dimensional view, select the windspeed label of one of the table view cells, and set its horizontal content hugging priority to 251. Because the horizontal content hugging priority of the temperature label is also set to 251, this change results in an ambiguous layout. Reveal evaluates the changes, spots the problem, and warns us that it detected an issue. Reveal displays the layout issue in the Layout Inspector if you click the small yellow triangle in the view hierarchy. Even though Reveal doesn't make suggestions to resolve the layout issue, it's clear that Reveal is a very helpful tool to debug Auto Layout issues. Layer Inspector

The inspector on the right is the Layer Inspector. As the name implies, it shows the properties of the backing layer of the currently selected view. Speed, Performance, and Reliability

Some of the most important features of Reveal aren't immediately obvious. They become visible once you've worked with Xcode's view debugger for a while. Reveal is fast, performant, and very reliable. I can't remember the last time Reveal failed on me. This is obviously the result of a committed development team and the frequent updates.

It can often take several seconds or longer for Xcode's view debugger to capture a snapshot of the view hierarchy and sometimes it fails without a clear reason. This doesn't happen often, if ever, when you're working with Reveal. Reveal also has the upper hand in terms of debugging Auto Layout issues. Let me show you what I mean. Revisit the project in Xcode and open WeatherDayTableViewCell.swift. In awakeFromNib(), we fix the width of iconImageView to 100 points.

Run the application and refresh the snapshot in Reveal by clicking the refresh button in the status view, choosing View > Refresh from the menu, or pressing Command + R. Reveal displays Auto Layout warnings and errors. Warnings, which we covered a few moments ago, are similar to the runtime issues reported by Xcode's built-in view debugger. They indicate that the layout is ambiguous. As you may remember from Debugging Applications With Xcode, errors are not reported by Xcode's view debugger. They indicate that a layout is unsatisfiable and one or more constraints were broken to satisfy the layout.

The layout engine doesn't like the change we made in the WeatherDayTableViewCell class. We set the width of the image view to 60 points in Interface Builder, which conflicts with the constraint we added in code. The output in Xcode's console confirms this.

Xcode's view debugger doesn't report these types of errors, but Reveal does. The error shows up as a small red triangle in the view hierarchy on the left, indicating that Auto Layout encountered an error. The layout is unsatisfiable and one or more constraints were broken to satisfy the layout. If we click the small red triangle, the list of constraints expands and the Layout Inspector on the right opens. Notice that the Layout Inspector is badged with a small red triangle to indicate that Reveal encountered one or more errors. Reveal informs us that the constraint we selected has been broken by the layout engine because it couldn't be satisfied. That's also what Xcode reports in the console. The difference is that Reveal highlights the problematic constraints in the view hierarchy, making it much easier to debug the issue.


Even though I showed you in this episode how to use Reveal to debug an iOS application, Reveal also supports tvOS applications and app extensions. The developers also told me that Reveal has rudimentary support for watchOS applications.

Some of Reveal's features illustrate the amount of effort the team has put into the application. For example, it's possible to save a view hierarchy to a file, which can be useful if you're working in a team or if you want to revisit a snapshot at a later point. Reveal supports multiple tabs and windows, which make it easy to compare view hierarchies side by side.

Reveal integrates nicely with Touch Bar and it has built-in support for AppCode. The application continues to improve with every release and it's worth the investment. Download Reveal and give it a try.


