6

不明なクラスのすべてのプロパティとすべてのプロパティのクラスのリストを取得しようとしています。その時点で、オブジェクトのすべてのプロパティのリストを取得します (すべてのスーパークラスを取得するために再帰的に行います)。この投稿に励まされました

+ (NSArray *)classPropsFor:(Class)klass
{    
    NSLog(@"Properties for class:%@", klass);
    if (klass == NULL || klass == [NSObject class]) {
        return nil;
    }

    NSMutableArray *results = [[NSMutableArray 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) {
            NSString *propertyName = [NSString stringWithUTF8String:propName];
            [results addObject:propertyName];
        }
        NSArray* dict = [self classPropsFor:[klass superclass]];
        [results addObjectsFromArray:dict];
    }
    free(properties);

    return [NSArray arrayWithArray:results];
}

だから今、私はすべてのプロパティのクラスが欲しいので、私はそうします:

NSArray* properties = [PropertyUtil classPropsFor:[self class]];
for (NSString* property in properties) {
    id value= [self valueForKey:property];
    NSLog(@"Value class for key: %@ is %@", property, [value class]);
}

問題は、NSStrings では機能するか、カスタム クラスでは機能しないため、null が返されることです。内部に他のオブジェクトを持つことができるオブジェクトを表す辞書を再帰的に作成したいのですが、すべてのプロパティのクラスを知る必要があると思いますが、それは可能ですか?

4

4 に答える 4

7

このための小さなメソッドを作成しました。

// Simple as.
Class propertyClass = [customObject classOfPropertyNamed:propertyName];

多くの点で最適化できますが、私はそれが大好きです。


実装は次のようになります。

-(Class)classOfPropertyNamed:(NSString*) propertyName
{
    // Get Class of property to be populated.
    Class propertyClass = nil;
    objc_property_t property = class_getProperty([self class], [propertyName UTF8String]);
    NSString *propertyAttributes = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
    NSArray *splitPropertyAttributes = [propertyAttributes componentsSeparatedByString:@","];
    if (splitPropertyAttributes.count > 0)
    {
        // xcdoc://ios//library/prerelease/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
        NSString *encodeType = splitPropertyAttributes[0];
        NSArray *splitEncodeType = [encodeType componentsSeparatedByString:@"\""];
        NSString *className = splitEncodeType[1];
        propertyClass = NSClassFromString(className);
    }
    return propertyClass;
}

これは、 と呼ばれる開発中のオブジェクト表現内のeppz!kitNSObject+EPPZRepresentable.hの一部です。それは実際にあなたが本来達成しようとしていることを行います。

// Works vica-versa.
NSDictionary *representation = [customObject dictionaryRepresentation];
CustomClass = [CustomClass representableWithDictionaryRepresentation:representation];

多くの型をエンコードし、トラフ コレクションを反復し、CoreGraphics 型、UIColors を表し、オブジェクト参照も表現/再構築します。


新しいバージョンでは、 C 型名名前付き構造体型も同様に返されます。

NSLog(@"%@", [self typeOfPropertyNamed:@"index"]); // unsigned int
NSLog(@"%@", [self typeOfPropertyNamed:@"area"]); // CGRect
NSLog(@"%@", [self typeOfPropertyNamed:@"keyColor"]); // UIColor

eppz!modelの一部です。https://github.com/eppz/eppz.model/blob/master/eppz!model/NSObject%2BEPPZModel_inspecting.m#L111でメソッドの実装を自由に使用してください。

于 2014-01-16T16:12:08.957 に答える
2

更新しました

これは、 の値では機能しませんnil。代わりに、ランタイム C API を使用して、対応する ivar またはアクセサ メソッドからクラスを取得する必要があります。

于 2012-05-21T14:53:04.880 に答える
2

を格納すると同時に、各プロパティのクラスを (文字列として) 格納する必要がありますpropertyName。プロパティ名をキー、クラス名を値とするディクショナリとして、またはその逆の場合もあります。

クラス名を取得するには、次のようにします (これを宣言の直後に置きますpropertyName)。

NSString* propertyAttributes = [NSString stringWithUTF8String:property_getAttributes(property)];
NSArray* splitPropertyAttributes = [propertyAttributes componentsSeparatedByString:@"\""];
if ([splitPropertyAttributes count] >= 2)
{
    NSLog(@"Class of property: %@", [splitPropertyAttributes objectAtIndex:1]);
}

文字列処理コードは、属性に多数の情報が含まれているためです。正確な詳細は、https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection で指定されています。 html

于 2012-05-21T15:01:36.693 に答える
0

以下を NSObject カテゴリに追加すると、うまくいきます。

- (Class) classForKeyPath:(NSString*)keyPath {
    Class class = 0;

    unsigned int n = 0;
    objc_property_t* properties = class_copyPropertyList(self.class, &n);
    for (unsigned int i=0; i<n; i++) {
        objc_property_t* property = properties + i;
        NSString* name = [NSString stringWithCString:property_getName(*property) encoding:NSUTF8StringEncoding];
        if (![keyPath isEqualToString:name]) continue;

        const char* attributes = property_getAttributes(*property);
        if (attributes[1] == '@') {
            NSMutableString* className = [NSMutableString new];
            for (int j=3; attributes[j] && attributes[j]!='"'; j++)
                [className appendFormat:@"%c", attributes[j]];
            class = NSClassFromString(className);
        }
        break;
    }
    free(properties);

    return class;
}
于 2016-02-24T19:17:33.103 に答える