Recursivedescription Method in Swift

recursiveDescription method in Swift?

In order to access private / undocumented Objective-C API (like the -recursiveDescription method on UIView) from Swift you can do the following:

  1. Create a new Objective-C category on the class the private method is defined in (e.g. UIView).
  2. Hit Yes if Xcode asks you about configuring an bridging header. (If you have already an bridging header in your project this step will be skipped).
  3. The implementation file (.m) of the category can be removed.
  4. Declare the private method in the category header:

    // UIView+Debugging.h

    @interface UIView (Debugging)
    - (id)recursiveDescription;
    @end

Now you can set a breakpoint and print out the recursive description in LLDB:

po view.recursiveDescription() as NSString

Is there a recursiveDescription method for the view controller hierarchy?

Update - similar functionality is now available in Apple-supplied form as the _printHierarchy method, so you don't need this category any more.

There is now:

Github: Recursive description category for view controllers.

This adds a recursiveDescription method to UIViewController which prints out the view controller hierarchy. Excellent for checking if you are adding and removing your child view controllers properly.

The code is very simple, included here as well as the GitHub link above:

@implementation UIViewController (RecursiveDescription)

-(NSString*)recursiveDescription
{
NSMutableString *description = [NSMutableString stringWithFormat:@"\n"];
[self addDescriptionToString:description indentLevel:0];
return description;
}

-(void)addDescriptionToString:(NSMutableString*)string indentLevel:(NSInteger)indentLevel
{
NSString *padding = [@"" stringByPaddingToLength:indentLevel withString:@" " startingAtIndex:0];
[string appendString:padding];
[string appendFormat:@"%@, %@",[self debugDescription],NSStringFromCGRect(self.view.frame)];

for (UIViewController *childController in self.childViewControllers)
{
[string appendFormat:@"\n%@>",padding];
[childController addDescriptionToString:string indentLevel:indentLevel + 1];
}
}

@end

How do I inspect the view hierarchy in iOS?

Xcode 6 now has 3D view hierarchy inspection built in like Reveal App and Spark Inspector.

Sample Image

Click on the "Debug View Hierarchy" button while your app is running to pause execution and inspect the views at the current moment.

Sample Image

More info at Apple's documentation.

Can I see the view hierarchy I have in my app while debugging in Xcode?

You might find lldb comes to the rescue with 'recursiveDescription'. Simply set a breakpoint at the point where you are interested in the view hierarchy. If for example you want everything in the window you can type

(lldb) po [[[[UIApplication sharedApplication] windows] firstObject] recursiveDescription]

Alternatively, I often find that when debugging views I am mostly interested in the hierarchy for a particular view. In that instance you can hook straight in to the point in code you are curious about (for example the viewDidAppear: method) and type:

(lldb) po [self.view recursiveDescription]

Note: With Xcode 6 Apple have added realtime view debugging which you can access from the debug bar. Real Time View Debugging Xcode 6

I need to inspect the view hierarchy on an iPhone program

Along the lines of what Yannick suggests, Erica Sadun has code here that pretty-prints the view hierarchy (with class and frame information). You can make this into a UIView category with the following interface:

#import <UIKit/UIKit.h>

@interface UIView (ExploreViews)

- (void)exploreViewAtLevel:(int)level;

@end

and implementation:

#import "UIView+ExploreViews.h"

void doLog(int level, id formatstring,...)
{
int i;
for (i = 0; i < level; i++) printf(" ");

va_list arglist;
if (formatstring)
{
va_start(arglist, formatstring);
id outstring = [[NSString alloc] initWithFormat:formatstring arguments:arglist];
fprintf(stderr, "%s\n", [outstring UTF8String]);
va_end(arglist);
}
}

@implementation UIView (ExploreViews)

- (void)exploreViewAtLevel:(int)level;
{
doLog(level, @"%@", [[self class] description]);
doLog(level, @"%@", NSStringFromCGRect([self frame]));
for (UIView *subview in [self subviews])
[subview exploreViewAtLevel:(level + 1)];
}

@end

How to print a control hierarchy in Cocoa?

I don't know what exactly DebugPrintControlHierarchy printed, but NSView has a useful method call _subtreeDescription which returns a string describing the entire hierarchy beneath the receiver, include classes, frames, and other useful information.

Don't be scared about the leading _ underscore. It's not public API, but it is sanctioned for public use in gdb. You can see it mentioned in the AppKit release notes along with some sample output.

Presenting a specific view controller from AppDelegate

I suggest you use applicationWillEnterForeground:, not applicationDidBecomeActive:, because it works better with multitasking gestures. For example, you don't want to put up the lock screen if the user double-clicks the home button to display the task bar, and then dismisses the task bar without changing apps.

Presumably your AppDelegate has a window property, and you know that your window's root view controller is a UINavigationController.

- (void)applicationWillEnterForeground:(UIApplication *)application {
PasscodeViewController *pvc = [[PasscodeViewController alloc] init];
[(UINavigationController *)self.window.rootViewController pushViewController:pvc animated:NO];
// [pvc release]; if not using ARC
}

Xcode 13.3 warning: 'self' refers to the method '{object}.self', which may be unexpected

You can fix by changing the lets to lazy var's

private lazy var _switch2: UISwitch = {
let _switch = UISwitch()
_switch.translatesAutoresizingMaskIntoConstraints = false
_switch.addTarget(self, action: #selector(didToggleSwitch), for: .valueChanged)
return _switch
}()

The Xcode fix-it suggestion is just wrong.



Related Topics



Leave a reply



Submit