Objective-C Introspection/Reflection

Objective CCocoaXcodeReflectionIntrospection

Objective C Problem Overview


Is there a built in method, function, API, commonly accepted way, etc. to dump the contents of an instantiated object in Objective-C, specifically in Apple's Cocoa/Cocoa-Touch environment?

I want to be able to do something like

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

and have the object's instance variable names and values displayed, along with any methods available to call at run time. Ideally in an easy to read format.

For developers familiar with PHP, I'm basically looking for the equivalent of the reflection functions (var_dump(), get_class_methods()) and the OO Reflection API.

Objective C Solutions


Solution 1 - Objective C

UPDATE: Anyone looking to do this kind of stuff might want to check out Mike Ash's ObjC wrapper for the Objective-C runtime.

This is more or less how you'd go about it:

#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);
}

From there, it's easy to get the actual values of an instance's properties, but you have to check to see if they are primitive types or objects, so I was too lazy to put it in. You could also choose to scan the inheritance chain to get all the properties defined on an object. Then there are methods defined on categories, and more... But almost everything is readily available.

Here's an excerpt of what the above code dumps for 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
    );
}

Solution 2 - Objective C

Short of the description method (like .toString() in Java), I haven't heard of one that was built in, but it wouldn't be too difficult to create one. The Objective-C Runtime Reference has a bunch of functions you can use to get information about an object's instance variables, methods, properties, etc.

Solution 3 - Objective C

Here's what I am currently using to automatically print class variables, in a library for eventual public release - it works by dumping all properties from the instance class all the way back up the inheritance tree. Thanks to KVC you don't need to care if a property is a primitive type or not (for most types).

// 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]]];
}

Solution 4 - Objective C

I made a couple of tweaks to Kendall's code for printing property values, which came in very handy for me. I defined it as an instance method instead of a class method, as that's how the superclass recursion calls it. I also added exception handling for non-KVO-compliant properties, and added line breaks to the output to make it easier to read (and diff):

-(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) 
        {
         @try {
            id value = [instance valueForKey:propNameString];
            [propPrint appendString:[NSString stringWithFormat:@"%@=%@\n", propNameString, value]];
         }
         @catch (NSException *exception) {
            [propPrint appendString:[NSString stringWithFormat:@"Can't get value for property %@ through KVO\n", propNameString]];
         }
        }
    }
    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;
}

Solution 5 - Objective C

Honestly, the right tool for this job is Xcode's debugger. It has all this information easily accessible in a visual way. Take the time to learn how to use it, it's a really powerful tool.

More information:

Using the Debugger

Outdated Xcode Debugging Guide - archived by Apple

About Debugging with Xcode - archived by Apple

About LLDB and Debugging - archived by Apple

Debugging with GDB - archived by Apple

SpriteKit Debugging Guide - archived by Apple

Debugging Programming Topics for Core Foundation - archived by Apple

Solution 6 - Objective C

I have made cocoapod out of this, https://github.com/neoneye/autodescribe

I have modified Christopher Pickslay's code and made it a category on NSObject and also added a unittest to it. Here is how to use it:

@interface TestPerson : NSObject

@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSNumber *age;

@end

@implementation TestPerson

// empty

@end

@implementation NSObject_AutoDescribeTests

-(void)test0 {
    TestPerson *person = [TestPerson new];
    person.firstName = @"John";
    person.lastName = @"Doe";
    person.age = [NSNumber numberWithFloat:33.33];
    NSString *actual = [person autoDescribe];
    NSString *expected = @"firstName=John\nlastName=Doe\nage=33.33";
    STAssertEqualObjects(actual, expected, nil);
}

@end

Solution 7 - Objective C

I am confused with Introspection and Refection before, so get some information below.

Introspection is the capability for object to check which type it is, or protocol it conformed, or selector it can response. The objc api such as isKindOfClass/isMemberOfClass/conformsToProtocol/respondsToSelector etc.

Refection capability is further than Introspection,It’s not only can get object information but also can operation object meta-data, properties and functions. such as object_setClass can modify object type.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlan StormView Question on Stackoverflow
Solution 1 - Objective CFelixyzView Answer on Stackoverflow
Solution 2 - Objective CDave DeLongView Answer on Stackoverflow
Solution 3 - Objective CKendall Helmstetter GelnerView Answer on Stackoverflow
Solution 4 - Objective CChristopher PickslayView Answer on Stackoverflow
Solution 5 - Objective CColin BarrettView Answer on Stackoverflow
Solution 6 - Objective CneoneyeView Answer on Stackoverflow
Solution 7 - Objective CJoneView Answer on Stackoverflow