Online Book Reader

Home Category

iOS Recipes - Matt Drance [76]

By Root 208 0
and formalizing your logic so it can be hunted down, refactored, and debugged easily and predictably.

Recipe 38 Scan and Traverse View Hierarchies

Problem

You have a complex view hierarchy that you want to visualize and explore very simply in order to understand it better before making any changes. You want to see the hierarchy tree—whether it came from a nib, your code, or someone else’s—and you want to reliably find subviews of a certain type that may lie within.

Solution

Apple’s Technical Note TN2239, “iOS Debugging Magic,” introduces a hidden API on UIView called ‑recursiveDescription, which can be used from the debugger to see an ASCII visualization of a particular view’s hierarchy. This is useful for understanding the structure and layout of your UI at a given point in time, which makes it a very valuable debugging tool.

But ‑recursiveDescription can be overwhelming for complex hierarchies, both because a view’s description is verbose and because there may be a lot of views. Figure 37, Analyzing view hierarchies shows an example of a hierarchy you may not want to see fully printed out in the console. This recipe explores the technique behind producing a customized “ASCII tree” for inspection during development and debugging. We’ll do this in a UIView category so it can be called on any UIView or subclass of UIView—even views we didn’t create. We’ll also declare a method that searches the hierarchy for views matching a given Objective-C class in case we want to isolate a certain type of view while inspecting our UI.

Deep hierarchies can be tough to manage, especially if they’re constructed dynamically. How can you get insight on the layout to see what you might be missing?

Figure 37. Analyzing view hierarchies

* * *

Let’s take a look at the first two methods our category declares:

PrintSubviews/Classes/UIView+PRPSubviewTraversal.h

- (void)prp_printSubviews;

- (void)prp_printSubviewsWithIndentString:(NSString *)indentString;

It contains a few supporting methods, but the first one we want to explore is ‑prp_printSubviewsWithIndentString:. This method works recursively through the view’s entire hierarchy, modifying the indentString parameter with each pass to increase the indentation for the next hierarchy level.

The ‑prp_printSubviewsWithIndentString: method starts by ensuring the passed indentString is valid for printing; if we’re deep into the hierarchy, then this string is a combination of spaces and pipes constructed by prior invocations. The string is prepended to a description of the current view. In this example, we simply use the class name, but we could add more information such as the view’s frame or number of subviews.

PrintSubviews/Classes/UIView+PRPSubviewTraversal.m

if (indentString == nil) indentString = @"";

NSString *viewDescription = NSStringFromClass([self class]);

printf("%s+-%s\n", [indentString UTF8String],

[viewDescription UTF8String]);

Next, we prepare the indentString for the next hierarchy level (if there is one). If the current view has siblings, we want to draw a line connecting them, so we add a pipe character that will appear directly below the string that was just printed. If there are no siblings, we just add a space so the indentation remains consistent.

PrintSubviews/Classes/UIView+PRPSubviewTraversal.m

if (self.subviews) {

NSArray *siblings = self.superview.subviews;

if ([siblings count] > 1 &&

([siblings indexOfObject:self] < [siblings count]-1)) {

indentString = [indentString stringByAppendingString:@"| "];

} else {

indentString = [indentString stringByAppendingString:@" "];

}

With the indent string fully prepared for the next hierarchy level, we pass it to ‑prp_printSubviewsWithIndentString: for each of the subviews. This continues generating the recursive printout of the hierarchy. When the algorithm hits a leaf in the tree, the subviews property is empty and the recursion ends.

PrintSubviews/Classes/UIView+PRPSubviewTraversal.m

for (UIView *subview in self.subviews) {

[subview prp_printSubviewsWithIndentString:indentString];

Return Main Page Previous Page Next Page

®Online Book Reader