views:

279

answers:

4

Is there a way to obtain something like a dictionary of all key-value pairs of a class?

+4  A: 

You'd have to roll your own using the Objective-C Runtime functions. Here's some very basic sample code. Note that getting the ivars of a class doesn't get the ivars of its superclass. You'd need to do that explicitly, but the functions are all there in the runtime.

#import <objc/objc-runtime.h>
#include <inttypes.h>
#include <Foundation/Foundation.h>

@interface Foo : NSObject
{
    int i1;
}
@end
@implementation Foo
@end

@interface Bar : Foo
{
    NSString* s1;
}

@end
@implementation Bar
@end

int main(int argc, char** argv)
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    unsigned int count;
    Ivar* ivars = class_copyIvarList([Bar class], &count);
    for(unsigned int i = 0; i < count; ++i)
    {
        NSLog(@"%@::%s", [Bar class], ivar_getName(ivars[i]));
    }
    free(ivars);


    [pool release];
}
nall
Since `class_copyIvarList` has `copy` in the name, you're responsible for cleaning up the memory. Hence, you also need `free(ivars);` in there.
Dave DeLong
totally right. thanks.
nall
+3  A: 

I'm not sure for just ivars but if you have them defined as properties it is possible to access the available properties on a class.

I've been using SQLitePersistentObjects for a couple projects and it has some helpful code that gets the properties defined on the class to use when figuring out serialization to and from sqlite.

It uses the function class_copyPropertyList to get the available list of properties on a class.

More specifically:

+(NSDictionary *)propertiesWithEncodedTypes
{

    // DO NOT use a static variable to cache this, it will cause problem with subclasses of classes that are subclasses of SQLitePersistentObject

    // Recurse up the classes, but stop at NSObject. Each class only reports its own properties, not those inherited from its superclass
    NSMutableDictionary *theProps;

    if ([self superclass] != [NSObject class])
     theProps = (NSMutableDictionary *)[[self superclass] propertiesWithEncodedTypes];
    else
     theProps = [NSMutableDictionary dictionary];

    unsigned int outCount;


    objc_property_t *propList = class_copyPropertyList([self class], &outCount);
    int i;

    // Loop through properties and add declarations for the create
    for (i=0; i < outCount; i++)
    {
     objc_property_t * oneProp = propList + i;
     NSString *propName = [NSString stringWithUTF8String:property_getName(*oneProp)];
     NSString *attrs = [NSString stringWithUTF8String: property_getAttributes(*oneProp)];
     NSArray *attrParts = [attrs componentsSeparatedByString:@","];
     if (attrParts != nil)
     {
      if ([attrParts count] > 0)
      {
       NSString *propType = [[attrParts objectAtIndex:0] substringFromIndex:1];
       [theProps setObject:propType forKey:propName];
      }
     }
    }

  free(propList);

    return theProps; 
}

This returns a dictionary of the properties - you'll need to do some investigating of the results you get back but you should be able to get what you need if you're using properties.

paulthenerd
+3  A: 

Yep, totally possible:

int numIvars = 0;
Ivar * ivars = class_copyIvarList([anInstanceOfAClass class], &numIvars);
NSMutableDictionary * pairs = [NSMutableDictionary dictionary];
for (int i = 0; i < numIvars; ++i) {
  Ivar ivar = ivars[i];
  NSString * ivarName = [NSString stringWithCString:ivar_getName(ivar) encoding:NSUTF8StringEncoding];
  id ivarValue = [anInstanceOfAClass valueForKey:ivarName];
  [pairs setObject:ivarValue forKey:ivarName];
}
free(ivars);
NSLog(@"%@", pairs);
Dave DeLong
A: 

I posted a runtime browser project here: http://x-cake.ning.com/profiles/blogs/browsing-the-objc-runtime-on

NSResponder