目标C反思/反思

Ala*_*orm 78 reflection xcode cocoa introspection objective-c

是否有内置的方法,函数,API,普遍接受的方式等来转储Objective C中实例化对象的内容,特别是在Apple的Cocoa/Cocoa-Touch环境中?

我希望能够做类似的事情

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

并显示对象的实例变量名称和值,以及可在运行时调用的任何方法.理想情况下,易于阅读的格式.

对于熟悉PHP的开发人员,我基本上寻找等效的反射函数(var_dump(),get_class_methods())和OO Reflection API.

Fel*_*xyz 112

更新:任何想要做这种事情的人可能想要查看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);
}
Run Code Online (Sandbox Code Playgroud)

从那里,很容易获得实例属性的实际值,但是你必须检查它们是原始类型还是对象,所以我懒得把它放进去.你也可以选择扫描继承链到获取对象上定义的所有属性.然后有类别定义的方法,更多......但几乎所有东西都是现成的.

以下是上述代码转储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
    );
}
Run Code Online (Sandbox Code Playgroud)

  • +1这几乎是我做的事情(使它成为'NSObject`类别).但是,你必须`free()`你的`ivars`,`properties`和`methods`数组,否则你就是泄漏了它们. (6认同)
  • 我们不能看到伊娃的价值吗? (4认同)
  • ......还有他们的类型.我注意到你说它可以做到,但你似乎对此有了比我更好的理解.您是否能够在某些时候使用代码更新此信息以获取ivars和属性的值和类型? (2认同)

Dav*_*ong 12

除了description方法之外(比如Java中的.toString()),我还没有听说过内置的那个,但创建一个并不太难. Objective-C运行时参考有许多函数可用于获取有关对象的实例变量,方法,属性等的信息.

  • 如果你打算回答一下,请礼貌地发表评论. (7认同)

Ken*_*ner 8

这是我目前用于自动打印类变量的库,用于最终公开发布 - 它通过从实例类转储所有属性一直备份到继承树.感谢KVC,您不需要关心属性是否是原始类型(对于大多数类型).

// Finds all properties of an object, and prints each one out as part of a string describing the class.
+ (NSString *) autoDescribe:(id)instance classType:(Class)classType
{
    NSUInteger count;
    objc_property_t *propList = class_copyPropertyList(classType, &count);
    NSMutableString *propPrint = [NSMutableString string];

    for ( int i = 0; i < count; i++ )
    {
        objc_property_t property = propList[i];

        const char *propName = property_getName(property);
        NSString *propNameString =[NSString stringWithCString:propName encoding:NSASCIIStringEncoding];

        if(propName) 
        {
            id value = [instance valueForKey:propNameString];
            [propPrint appendString:[NSString stringWithFormat:@"%@=%@ ; ", propNameString, value]];
        }
    }
    free(propList);


    // Now see if we need to map any superclasses as well.
    Class superClass = class_getSuperclass( classType );
    if ( superClass != nil && ! [superClass isEqual:[NSObject class]] )
    {
        NSString *superString = [self autoDescribe:instance classType:superClass];
        [propPrint appendString:superString];
    }

    return propPrint;
}

+ (NSString *) autoDescribe:(id)instance
{
    NSString *headerString = [NSString stringWithFormat:@"%@:%p:: ",[instance class], instance];
    return [headerString stringByAppendingString:[self autoDescribe:instance classType:[instance class]]];
}
Run Code Online (Sandbox Code Playgroud)