1. ホーム
  2. objective-c

Objective-Cのイントロスペクション/リフレクション

2023-08-12 04:07:38

質問

Objective-C、特に Apple の Cocoa/Cocoa-Touch 環境で、インスタンス化されたオブジェクトの内容をダンプするための組み込みのメソッド、関数、API、一般に認められた方法などはありますか。

私は以下のようなことを行えるようにしたいです。

MyType *the_thing = [[MyType alloc] init];
NSString *the_dump = [the_thing dump]; //pseudo code
NSLog("Dumped Contents: %@", the_dump);

で、オブジェクトのインスタンス変数の名前と値、および実行時に呼び出せるメソッドが表示されます。読みやすい形式が理想的です。

PHPに詳しい開発者のために、私は基本的にリフレクション関数に相当するものを探しています( var_dump() , get_class_methods() ) と OO Reflection API があります。

どのように解決するのですか?

UPDATEしてください。 このようなことをしたい人は、以下をチェックするとよいでしょう。 Mike AshによるObjective-CランタイムのためのObjCラッパーです。 .

多かれ少なかれ、こんな感じでしょうか。

#import <objc/runtime.h>

. . . 

-(void)dumpInfo
{
    Class clazz = [self class];
    u_int count;

    Ivar* ivars = class_copyIvarList(clazz, &count);
    NSMutableArray* ivarArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count ; i++)
    {
        const char* ivarName = ivar_getName(ivars[i]);
        [ivarArray addObject:[NSString  stringWithCString:ivarName encoding:NSUTF8StringEncoding]];
    }
    free(ivars);

    objc_property_t* properties = class_copyPropertyList(clazz, &count);
    NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count ; i++)
    {
        const char* propertyName = property_getName(properties[i]);
        [propertyArray addObject:[NSString  stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
    }
    free(properties);

    Method* methods = class_copyMethodList(clazz, &count);
    NSMutableArray* methodArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count ; i++)
    {
        SEL selector = method_getName(methods[i]);
        const char* methodName = sel_getName(selector);
        [methodArray addObject:[NSString  stringWithCString:methodName encoding:NSUTF8StringEncoding]];
    }
    free(methods);

    NSDictionary* classDump = [NSDictionary dictionaryWithObjectsAndKeys:
                               ivarArray, @"ivars",
                               propertyArray, @"properties",
                               methodArray, @"methods",
                               nil];

    NSLog(@"%@", classDump);
}

そこから、インスタンスのプロパティの実際の値を取得するのは簡単ですが、プリミティブ型かオブジェクトかを確認する必要があるので、面倒なので入れませんでした。また、継承チェーンをスキャンして 全て オブジェクトに定義されたプロパティを取得することもできます。それから、カテゴリに定義されたメソッド、さらに...。しかし、ほとんどすべてがすぐに利用可能です。

以下は、上記のコードがUILabelに対してダンプする内容の抜粋です。

{
    ivars =     (
        "_size",
        "_text",
        "_color",
        "_highlightedColor",
        "_shadowColor",
        "_font",
        "_shadowOffset",
        "_minFontSize",
        "_actualFontSize",
        "_numberOfLines",
        "_lastLineBaseline",
        "_lineSpacing",
        "_textLabelFlags"
    );
    methods =     (
        rawSize,
        "setRawSize:",
        "drawContentsInRect:",
        "textRectForBounds:",
        "textSizeForWidth:",
        . . .
    );
    properties =     (
        text,
        font,
        textColor,
        shadowColor,
        shadowOffset,
        textAlignment,
        lineBreakMode,
        highlightedTextColor,
        highlighted,
        enabled,
        numberOfLines,
        adjustsFontSizeToFitWidth,
        minimumFontSize,
        baselineAdjustment,
        "_lastLineBaseline",
        lineSpacing,
        userInteractionEnabled
    );
}