Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List of class properties in Objective-C

People also ask

What is a property in Objective-C?

Objective-C properties offer a way to define the information that a class is intended to encapsulate. As you saw in Properties Control Access to an Object's Values, property declarations are included in the interface for a class, like this: @interface XYZPerson : NSObject.

What is a class in Objective-C?

In Objective-C, a class is itself an object with an opaque type called Class . Classes can't have properties defined using the declaration syntax shown earlier for instances, but they can receive messages.

What are properties and instance variables in Objective-C and swift?

Therefore, as a fundamental principal of object-oriented programming, instance variables (ivars) are private—they are encapsulated by the class. By contrast, a property is a public value that may or may not correspond to an instance variable.


So more precisely, you want dynamic, runtime observaion of the properties, if I got it correctly. Do something like this (implement this method on self, the class you want to introspect):

#import <objc/runtime.h>

- (NSArray *)allPropertyNames
{
    unsigned count;
    objc_property_t *properties = class_copyPropertyList([self class], &count);

    NSMutableArray *rv = [NSMutableArray array];

    unsigned i;
    for (i = 0; i < count; i++)
    {
        objc_property_t property = properties[i];
        NSString *name = [NSString stringWithUTF8String:property_getName(property)];
        [rv addObject:name];
    }

    free(properties);

    return rv;
}

- (void *)pointerOfIvarForPropertyNamed:(NSString *)name
{
    objc_property_t property = class_getProperty([self class], [name UTF8String]);

    const char *attr = property_getAttributes(property);
    const char *ivarName = strchr(attr, 'V') + 1;

    Ivar ivar = object_getInstanceVariable(self, ivarName, NULL);

    return (char *)self + ivar_getOffset(ivar);
}

Use it like this:

SomeType myProperty;
NSArray *properties = [self allPropertyNames];
NSString *firstPropertyName = [properties objectAtIndex:0];
void *propertyIvarAddress = [self getPointerOfIvarForPropertyNamed:firstPropertyName];
myProperty = *(SomeType *)propertyIvarAddress;

// Simpler alternative using KVC:
myProperty = [self valueForKey:firstPropertyName];

Hope this helps.


use attributeKeys method of NSObject.

    for (NSString *key in [self attributeKeys]) {

        id attribute = [self valueForKey:key];

        if([attribute isKindOfClass:[UILabel  class]])
        {
         //put attribute to your array
        }
    }

Check out this link. It is an objective c wrapper over objective C runtime.

You can use code like below

uint count;
objc_property_t* properties = class_copyPropertyList(self.class, &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);

You must include the runtime headers

 #import<objc/runtime.h>
uint propertiesCount;
objc_property_t *classPropertiesArray = class_copyPropertyList([self class], &propertiesCount);
free(classPropertiesArray);

The answer by @user529758 won't work with ARC and it won't list the properties of any ancestor classes.

To fix this, you need to traverse up the class hierarchy, and use the ARC-compatible [NSObject valueForKey:] to get the property values.

Person.h:

#import <Foundation/Foundation.h>

extern NSMutableArray *propertyNamesOfClass(Class klass);

@interface Person : NSObject

@property (nonatomic) NSString *name;

@end

Person.m:

#import "Person.h"
#import <objc/runtime.h>

NSMutableArray *propertyNamesOfClass(Class klass) {
    unsigned int count;
    objc_property_t *properties = class_copyPropertyList(klass, &count);

    NSMutableArray *rv = [NSMutableArray array];

    for (unsigned int i = 0; i < count; i++)
    {
        objc_property_t property = properties[i];
        NSString *name = [NSString stringWithUTF8String:property_getName(property)];
        [rv addObject:name];
    }

    free(properties);

    return rv;
}

@implementation Person

- (NSMutableArray *)allPropertyNames {
    NSMutableArray *classes = [NSMutableArray array];
    Class currentClass = [self class];
    while (currentClass != nil && currentClass != [NSObject class]) {
        [classes addObject:currentClass];
        currentClass = class_getSuperclass(currentClass);
    }

    NSMutableArray *names = [NSMutableArray array];
    [classes enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(Class currentClass, NSUInteger idx, BOOL *stop) {
        [names addObjectsFromArray:propertyNamesOfClass(currentClass)];
    }];

    return names;
}

- (NSString*)description {
    NSMutableArray *keys = [self allPropertyNames];
    NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithCapacity:keys.count];
    [keys enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) {
        properties[key] = [self valueForKey:key];
    }];

    NSString *className = NSStringFromClass([self class]);
    return [NSString stringWithFormat:@"%@ : %@", className, properties];
}

Student.h:

#import "Person.h"

@interface Student : Person

@property (nonatomic) NSString *studentID;

@end

Student.m:

#import "Student.h"

@implementation Student

@end

main.m:

#import <Foundation/Foundation.h>
#import "Student.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Student *student = [[Student alloc] init];
        student.name = @"John Doe";
        student.studentID = @"123456789";
        NSLog(@"student - %@", student);
    }
    return 0;
}