为了账号安全,请及时绑定邮箱和手机立即绑定

获取Objective-C中的对象属性列表

获取Objective-C中的对象属性列表

慕标5832272 2019-08-15 15:13:43
获取Objective-C中的对象属性列表如何在Objective-C中获取给定对象属性的列表(以NSArray或的形式NSDictionary)?想象一下下面的场景:我已经定义了一个只扩展的父类NSObject,它将a NSString,a BOOL和一个NSData对象作为属性。然后我有几个扩展这个父类的类,每个类都添加了很多不同的属性。有没有什么方法可以在父类上实现一个遍历整个对象的实例方法,然后返回NSArray每个(子)类属性的一个,因为NSStrings它不在父类上,所以我以后可以使用这些NSString对于KVC?
查看完整描述

3 回答

?
拉丁的传说

TA贡献1789条经验 获得超8个赞

我自己设法得到了答案。通过使用Obj-C运行时库,我可以按照我想要的方式访问属性:

- (void)myMethod {
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    for(i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        const char *propName = property_getName(property);
        if(propName) {
            const char *propType = getPropertyType(property);
            NSString *propertyName = [NSString stringWithCString:propName
                                                                encoding:[NSString defaultCStringEncoding]];
            NSString *propertyType = [NSString stringWithCString:propType
                                                                encoding:[NSString defaultCStringEncoding]];
            ...
        }
    }
    free(properties);}

这要求我制作一个'getPropertyType'C函数,它主要取自Apple代码示例(现在不能记住确切的来源):

static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T') {
            if (strlen(attribute) <= 4) {
                break;
            }
            return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
        }
    }
    return "@";}


查看完整回答
反对 回复 2019-08-15
?
明月笑刀无情

TA贡献1828条经验 获得超4个赞

它实际上并不总是以0结束字符串。这可能会导致意外的结果,比如在尝试将其转换为UTF8时崩溃(我实际上有一个非常令人讨厌的崩溃因为这个。很有趣的调试它^^)。我通过实际从属性获取NSString然后调用cStringUsingEncoding来修复它:这就像现在的魅力。(也适用于ARC,至少对我而言)

所以这是我现在的代码版本:

// PropertyUtil.h#import @interface PropertyUtil : NSObject+ (NSDictionary *)classPropsFor:(Class)klass;@end// PropertyUtil.m#import "PropertyUtil.h"#import <objc/runtime.h>@implementation PropertyUtilstatic const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    //printf("attributes=%s\n", attributes);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // it's a C primitive type:
            /*
             if you want a list of what will be returned for these primitives, search online for
             "objective-c" "Property Attribute Description Examples"
             apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc.
             */
            NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
        else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            // it's an ObjC id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // it's another ObjC object type:
            NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
    }
    return "";}+ (NSDictionary *)classPropsFor:(Class)klass{
    if (klass == NULL) {
        return nil;
    }

    NSMutableDictionary *results = [[NSMutableDictionary alloc] init];

    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(klass, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        const char *propName = property_getName(property);
        if(propName) {
            const char *propType = getPropertyType(property);
            NSString *propertyName = [NSString stringWithUTF8String:propName];
            NSString *propertyType = [NSString stringWithUTF8String:propType];
            [results setObject:propertyType forKey:propertyName];
        }
    }
    free(properties);

    // returning a copy here to make sure the dictionary is immutable
    return [NSDictionary dictionaryWithDictionary:results];}@end


查看完整回答
反对 回复 2019-08-15
  • 3 回答
  • 0 关注
  • 618 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信