Hatena::ブログ(Diary)

24/7 twenty-four seven Twitter

東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン

Bloglinesで閲読登録 ADD TO Hatena::RSS Subscribe with livedoor Reader Add to Google

mail address

Follow me on twitter.

iPhone アプリケーション

Hatena touch LDR touch TV Listings LCD Clock MyWebClip MyWebClip LITE  Japan Subway Route Map こころくろっく 英辞郎 on the WEB for iPhone(アルク)
i-Radio くるりんぱ性格診断 英辞郎検索ランキング(アルク) kotobank - コトバンク miil

iPad アプリケーション

LCD Clock HD 「超」整理手帳 for the iPad

共著

2010-05-21

ビュー (UIView) の階層構造をダンプする非公開の便利メソッド

標準 SDK で提供されているクラスがどういう構造になってるか参考にしたいとか、ちょっとしたカスタマイズをしたいとか、そういうときにビュー構造をダンプしたりすることはよくあると思います。

下記のようなメソッドを書いてもいいのですが、実は UIView には便利なメソッドが提供されています。

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

それが次の2つです。recursiveDescription メソッドが使用できるのは iPhone OS 3.0 以降です。

- (NSString *)recursiveDescription;
- (NSDictionary *)scriptingInfoWithChildren;

試しに UIWebView について出力してみました。

<UIWebView: 0x4411240; frame = (0 0; 320 480); layer = <CALayer: 0x441f300>>
    <UIScroller: 0x442ac60; frame = (0 0; 320 480); clipsToBounds = YES; autoresize = H; layer = <CALayer: 0x442b000>>
        <UIImageView: 0x442c0c0; frame = (0 0; 54 54); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x442c0f0>>
        <UIImageView: 0x442c060; frame = (0 0; 54 54); transform = [0, 1, -1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x442c090>>
        <UIImageView: 0x442bb30; frame = (0 0; 54 54); transform = [0, -1, 1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x442c030>>
        <UIImageView: 0x442b090; frame = (0 0; 54 54); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x442b0c0>>
        <UIImageView: 0x442b030; frame = (-14.5 14.5; 30 1); transform = [0, 1, -1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x442b060>>
        <UIImageView: 0x4429850; frame = (-14.5 14.5; 30 1); transform = [0, -1, 1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4423c80>>
        <UIImageView: 0x4429540; frame = (0 0; 1 30); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4428800>>
        <UIImageView: 0x4427c10; frame = (0 0; 1 30); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4426e50>>
        <UIImageView: 0x4426d80; frame = (0 450; 320 30); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x441e530>>
        <UIImageView: 0x442b190; frame = (0 0; 320 30); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x442ba70>>
        <UIWebDocumentView: 0x4823600; frame = (0 0; 320 480); layer = <UIWebLayer: 0x4420ce0>>

UIWebView は謎が多いクラスですが、こうしてみると UIWebView は単なるコンテナで、その下の UIScroller がスクロール機構を提供していて、実際の HTML やリッチテキスト、PDF の表示は UIWebDocumentView か担っているという構造はよくわかりますね。


iPhone OS 3.2 以降では内部構造に少し変更が入っています。

下記は OS 3.2 上で実行した場合の出力です(出力形式も若干変更が入ってますね)。

<UIWebView: 0x551a6a0; frame = (0 0; 320 480); layer = <CALayer: 0x5539ee0>>
   | <UIScrollView: 0x55416b0; frame = (0 0; 320 480); clipsToBounds = YES; autoresize = H; layer = <CALayer: 0x5541a20>>
   |    | <UIImageView: 0x5542770; frame = (0 0; 54 54); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x55427a0>>
   |    | <UIImageView: 0x5542710; frame = (0 0; 54 54); transform = [0, 1, -1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x5542740>>
   |    | <UIImageView: 0x55426b0; frame = (0 0; 54 54); transform = [0, -1, 1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x55426e0>>
   |    | <UIImageView: 0x5542550; frame = (0 0; 54 54); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x5542580>>
   |    | <UIImageView: 0x55424f0; frame = (-14.5 14.5; 30 1); transform = [0, 1, -1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x5542520>>
   |    | <UIImageView: 0x5542490; frame = (-14.5 14.5; 30 1); transform = [0, -1, 1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x55424c0>>
   |    | <UIImageView: 0x5542430; frame = (0 0; 1 30); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x5542460>>
   |    | <UIImageView: 0x55423d0; frame = (0 0; 1 30); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x5542400>>
   |    | <UIImageView: 0x5542370; frame = (0 450; 320 30); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x55423a0>>
   |    | <UIImageView: 0x5542210; frame = (0 0; 320 30); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x5542240>>
   |    | <UIWebBrowserView: 0x6035000; frame = (0 0; 320 480); layer = <UIWebLayer: 0x5539ac0>>

UIScroller が UIScrollView に、UIWebDocumentView が UIWebBrowserView に変わっています。

このように UIWebView は内部構造がころころ変わるので、普通に使うのが一番なのですが、どうしても見た目や振る舞いを変更したいこともあると思いますので、たまに見ておくといいですね。


ちなみに、UIWebView は 3.2 から UIScrollViewDelegate プロトコルに準拠するようになったのですが、UIScrollViewDelegate 関連のコールバックは呼ばれませんでした。

単に UIWebView が UIScrollView を使用するようになったので、UIWebView クラスにその宣言が増えただけのようです。

スクロールのタイミングとか簡単に取れるかと期待したのですが、残念です。


下記は同じく謎の多い MKMapView についての出力です。

上が 3.1.3、下が 3.2 での出力です。こちらも若干ですが内部構造が変化しています。

<MKMapView: 0x4613ad0; frame = (0 0; 320 480); clipsToBounds = YES; layer = <CALayer: 0x4613d00>>
    <UIView: 0x4617220; frame = (0 0; 320 480); autoresizesSubviews = NO; layer = <CALayer: 0x4617250>>
        <MKScrollView: 0x461a8c0; baseClass = UIScrollView; frame = (0 0; 320 480); clipsToBounds = YES; autoresizesSubviews = NO; layer = <CALayer: 0x461ae80>>
            <MKMapLevelView: 0x461bdd0; baseClass = UITiledView; frame = (0 0; 512 512); layer = <CALayer: 0x46151d0>> mapType:0 offset:(0.000000,0.000000) zoomlevel:2
            <MKOverlayView: 0x46172a0; frame = (0 0; 512 512); autoresizesSubviews = NO; layer = <CALayer: 0x46172f0>>
    <UIImageView: 0x461c2a0; frame = (9 448; 69 23); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x461c440>>
<MKMapView: 0x5349ef0; frame = (0 0; 320 480); clipsToBounds = YES; layer = <CALayer: 0x534a1b0>>
   | <UIView: 0x534ed10; frame = (0 0; 320 480); autoresizesSubviews = NO; layer = <CALayer: 0x534ed40>>
   |    | <MKScrollView: 0x5352310; baseClass = UIScrollView; frame = (0 0; 320 480); clipsToBounds = YES; autoresizesSubviews = NO; layer = <CALayer: 0x53525f0>>
   |    |    | <MKMapTileView: 0x534de30; frame = (0 0; 512 512); transform = [1.90735e-06, 0, 0, 1.90735e-06, 0, 0]; layer = <MKTiledLayer: 0x534df80>>
   |    |    | <MKAnnotationContainerView: 0x534ed90; frame = (0 0; 512 512); autoresizesSubviews = NO; layer = <CALayer: 0x534ede0>>
   | <UIImageView: 0x534c060; frame = (9 448; 69 23); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x5352940>>

とおるとおる 2011/12/01 12:04 ARCの下では,使えなくなってみたいです。残念。

KishikawaKatsumiKishikawaKatsumi 2011/12/01 15:46 メソッドのプロトタイプ宣言がないからコンパイルが通らないだけですね。
カテゴリなどでプロトタイプ宣言を書けば使えますよ。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証