2012-05-21 39 views
6

我想獲得一個未知類的所有屬性和每個屬性的類的列表。到目前爲止,我得到一個對象的所有屬性的列表(我遞歸獲取所有的超類)。我在this postiOS獲取房產類

+ (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]); 
} 

問題是,它適用於NSString的或而不是自定義類,對於它返回我空值。我想遞歸地創建一個代表一個可以有其他對象的對象的字典,因爲我認爲我需要知道每個屬性的類,這是可能的嗎?

回答

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

+0

真棒,完美的作品!感謝您的幫助:) – Jpellat

+0

不客氣:) –

2

修訂

這對於那些nil值不起作用。相反,您應該使用運行時C API從相應的ivar或accessor方法獲取類。

+0

如果該屬性爲'nil',這將如何產生類? – jlehr

+0

謝謝!那麼看無零值:) – Jpellat

+0

不客氣。另一個考慮是調用訪問器方法可能會產生副作用 - 例如,惰性初始化 - 您可能不希望在此觸發。 – jlehr

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!kit一部分,內部的發展對象申述稱爲NSObject+EPPZRepresentable.h。它實際上是做你最初要做的。

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

它編碼多種類型,迭代槽集合,表示CoreGraphics中的類型,UIColors,也代表/重建對象的引用。


新版本吐出你回來甚至C類名命名結構類型還有:

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

,隨時https://github.com/eppz/eppz.model/blob/master/eppz!model/NSObject%2BEPPZModel_inspecting.m#L111

+3

它的作品就像一個魅力! – Kjuly

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; 
}