View階層をダンプする

今までいろいろなGUIツールキットを触ってきたが、必ず一度はコンテキストのビュー階層を列挙するコードを書いてみる。

iOSの場合、これを行うのはUIViewControllerのコンテキストであることが多いと思うが、その場合プロパティviewでルートのビューの参照が取得できるので、これを基点にビューをトラバースするコードを書けば良い。

dumpAllChildrenOfViewメソッド
-(void) dumpAllChildrenOfView:(UIView*) view depth:(int) d buffer:(NSMutableString*) b
{
    NSString *str = @"";
    for (int i = 0; i < d; i++)
    {
        str = [str stringByAppendingFormat: @"  "];
    }

    str = [str stringByAppendingFormat: @"%@%@\n", str, view.class];
    [b appendString: str];

    d++;
    for (UIView *child in [view subviews])
    {
        //recursive call
        [self dumpAllChildrenOfView:child depth: d buffer: b];
    }

}

こんな感じで。あとはViewControllerのコンテキストで呼び出せば良い。

テストには今回もHonepwnerプロジェクトの詳細ビューを使い、ツールバーボタンのIBActionで上記メソッドを呼び出すように、XcodeでIBActionを構成した。

enumerateViewAction メソッド (IBAction)
- (IBAction)enumerateViewAction:(id)sender
{
    NSMutableString* ms = [[NSMutableString alloc] init];
    [self dumpAllChildrenOfView:[self view] depth:1 buffer:ms];

    UIAlertView* al;
    @try
    {
        al = [[UIAlertView alloc]
                   initWithTitle: @""
                   message: ms
                   delegate: nil
                   cancelButtonTitle: @"OK"
                   otherButtonTitles:nil];
        [al show];
    }
    @finally 
    {
        [al release];
        NSLog(@"\n%@", ms);
        [ms release];
    }
}
実行結果

同メソッドはダイアログに表示する他にNSLogの出力も行っている。

2012-01-20 21:10:36.205 Homwpwner[314:f803]
   UIView
       UILabel
       UITextField
           UITextFieldRoundedRectBackgroundView
               UIImageView
               UIImageView
               UIImageView
           UITextFieldLabel
       UILabel
       UITextField
           UITextFieldRoundedRectBackgroundView
               UIImageView
               UIImageView
               UIImageView
           UITextFieldLabel
       UILabel
       UITextField
           UITextFieldRoundedRectBackgroundView
               UIImageView
               UIImageView
               UIImageView
           UITextFieldLabel
       UILabel
       UIImageView
       UIToolbar
           _UIToolbarBackground
           UIToolbarButton
               UIButton
                   UIImageView
                   UIImageView
                   UIButtonLabel
           UIToolbarButton
               UIButton
                   UIImageView
                   UIImageView
                   UIButtonLabel

これは興味深い。

例えば、プリミティブに見えていたUIButtonクラスもUIImageViewとUIButtonLabelのコンポジションで構成されている。
iOS UIKitにおけるViewの階層は実際にxib上で見えているビューだけで構成されている訳では無いことが分る。