Skip to content

Instantly share code, notes, and snippets.

@lilyball
Created August 3, 2010 03:01
Show Gist options
  • Save lilyball/505755 to your computer and use it in GitHub Desktop.
Save lilyball/505755 to your computer and use it in GitHub Desktop.
Method to iterate the properties on an object
/*
* objc+blocks.h
*
* Created by Kevin Ballard on 1/13/10.
*
*/
#import <objc/runtime.h>
enum {
PropertyIteratorFlagReadonly = (1 << 0),
PropertyIteratorFlagCopy = (1 << 1),
PropertyIteratorFlagRetain = (1 << 2),
PropertyIteratorFlagNonatomic = (1 << 3),
PropertyIteratorFlagDynamic = (1 << 4),
PropertyIteratorFlagWeak = (1 << 5),
PropertyIteratorFlagCollectable = (1 << 6),
};
typedef NSUInteger PropertyIteratorFlags;
typedef struct PropertyIteratorInfo {
NSString *name;
PropertyIteratorFlags flags;
NSString *typeEncoding;
SEL getter;
SEL setter;
NSString *ivar;
} PropertyIteratorInfo;
void objc_iterateProperties(id obj, void (^iterator)(PropertyIteratorInfo info));
/*
* objc+blocks.m
*
* Created by Kevin Ballard on 1/13/10.
*
*/
#include "objc+blocks.h"
void objc_iterateProperties(id obj, void (^iterator)(PropertyIteratorInfo info)) {
for (Class klass = [obj class]; klass != [NSObject class]; klass = [klass superclass]) {
unsigned int pCount;
objc_property_t *props = class_copyPropertyList(klass, &pCount);
for (unsigned int i = 0; i < pCount; i++) {
NSString *attrs = [NSString stringWithUTF8String:property_getAttributes(props[i])];
NSArray *comps = [attrs componentsSeparatedByString:@","];
PropertyIteratorInfo info = {0};
info.name = [NSString stringWithUTF8String:property_getName(props[i])];
for (NSString *comp in comps) {
unichar c = [comp characterAtIndex:0];
comp = [comp substringFromIndex:1];
switch (c) {
case 'T': // property type
info.typeEncoding = comp;
break;
case 'R': // readonly
info.flags |= PropertyIteratorFlagReadonly;
break;
case 'C': // copy
info.flags |= PropertyIteratorFlagCopy;
break;
case '&': // retain
info.flags |= PropertyIteratorFlagRetain;
break;
case 'N': // nonatomic
info.flags |= PropertyIteratorFlagNonatomic;
break;
case 'G': // getter
info.getter = NSSelectorFromString(comp);
break;
case 'S': // setter
info.setter = NSSelectorFromString(comp);
break;
case 'D': // dynamic
info.flags |= PropertyIteratorFlagDynamic;
break;
case 'W': // weak
info.flags |= PropertyIteratorFlagWeak;
break;
case 'P': // eligible for garbage collection
info.flags |= PropertyIteratorFlagCollectable;
break;
case 't': // old-style type encoding; ignore this
break;
case 'V': // backing ivar name
info.ivar = comp;
break;
}
}
if (info.setter == NULL && !(info.flags & PropertyIteratorFlagReadonly)) {
info.setter = NSSelectorFromString([@"set" stringByAppendingString:[info.name capitalizedString]]);
}
if (info.getter == NULL) {
info.getter = NSSelectorFromString(info.name);
}
iterator(info);
}
free(props);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment