我需要检查iPhone程序上的视图层次结构

时间:2010-02-26 16:51:28

标签: iphone xcode debugging

如何在模拟器上运行时确定iPhone程序的视图结构?

7 个答案:

答案 0 :(得分:61)

有一种内置的转储视图层次结构的方法:recursiveDescription

NSLog(@"%@", [view recursiveDescription]);

它将输出如下内容:

<UIView: 0x6a107c0; frame = (0 20; 320 460); autoresize = W+H; layer = […]
   | <UIRoundedRectButton: 0x6a103e0; frame = (124 196; 72 37); opaque = NO; […]
   |    | <UIButtonLabel: 0x6a117b0; frame = (19 8; 34 21); text = 'Test'; […]

请参阅:https://developer.apple.com/library/content/technotes/tn2239/_index.html

答案 1 :(得分:29)

您根本不必编写单个日志语句或更改代码。

点击暂停按钮。

enter image description here

在控制台中输入以下内容

po [[UIWindow keyWindow] recursiveDescription]

答案 2 :(得分:17)

这些答案都是-recursiveDescription的变体,但问题发布已经过去了大约三年,现在有更好的方法可以检查您的视图层次结构。 -recursiveDescription对于大型层次结构总是有点难以管理 - 您花费更多时间查看输出日志而不是编程!

以下是一些较新的解决方案:

  • 您可以使用DCIntrospect打印出视图层次结构和 查看属性,并获得一些很酷的屏幕调试标记。

    DCIntrospect View

  • 您可以使用Spark Inspector 查看应用的视图层次结构并在3D中与其进行交互。该 Spark Inspector有一个侧边栏,可以反映Interface Builder和您 可以在您的应用运行时调整您的观看次数。 (完全披露:我 我是此工具的首席开发人员 - 向我发送您的功能请求!)

    Spark Inspector Main Panel

  • 您可以使用PonyDebugger进行连接 适用于您应用的Chrome Inspector - 您可以查看应用的视图 DOM视图中的层次结构,它们还捕获网络流量, 这可能很有用。

    PonyDebugger Web View

答案 3 :(得分:10)

根据Yannick的建议,Erica Sadun的代码here可以打印视图层次结构(包含类和框架信息)。您可以使用以下界面将其转换为UIView类别:

#import <UIKit/UIKit.h>

@interface UIView (ExploreViews)

- (void)exploreViewAtLevel:(int)level;

@end

和实施:

#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

答案 4 :(得分:5)

试试这个魔法:

NSLog(@"%@", [self.view recursiveDescription]);

答案 5 :(得分:3)

你可以使用这样的算法:

-(void)inspectView:(UIView *)aView level:(NSString *)level {
    NSLog(@"Level:%@", level);
    NSLog(@"View:%@", aView);

    NSArray *arr = [aView subviews];
    for (int i=0;i<[arr count];i++) {
        [self inspectView:[arr objectAtIndex:i]
          level:[NSString stringWithFormat:@"%@/%d", level, i]];
    }
}

并在viewDidLoad中添加此行,例如:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self inspectView:self.viewControllers level:@""];
}

来源:view hierarchy

答案 6 :(得分:1)

我也处理过这个问题,我想出了一个单一的递归方法作为UIView上的Category。它只使用基本的基础类,因此它不像Erica的解决方案那么复杂。

这是分类方法:

- (void)printSubviewsWithIndentation:(int)indentation {

    NSArray *subviews = [self subviews];   

    for (int i = 0; i < [subviews count]; i++) {

        UIView *currentSubview = [subviews objectAtIndex:i];   

        NSMutableString *currentViewDescription = [[NSMutableString alloc] init];

        for (int j = 0; j <= indentation; j++) {
            [currentViewDescription appendString:@"   "];   // indent the description
        }

        // print whatever you want to know about the subview
        [currentViewDescription appendFormat:@"[%d]: class: '%@'", i, NSStringFromClass([currentSubview class])];

        // Log the description string to the console
        NSLog(@"%@", currentViewDescription);

        [currentViewDescription release];

        // the 'recursiveness' nature of this method
        [currentSubview printSubviewsWithIndentation:indentation+1];
    }
}

有关详细信息,请查看我关于此问题的博客文章:http://www.glimsoft.com/01/07/how-to-inspect-subviews-hierarchy-of-any-uiview/