2012-02-13 13 views
9

Chcę utworzyć klasę bazową Objective-C, która wykonuje operację na wszystkich właściwościach (różnych typów) w środowisku wykonawczym. Ponieważ nazwy i typy właściwości nie zawsze będą znane, jak mogę zrobić coś takiego?Pętla przez wszystkie właściwości obiektu w czasie wykonywania

@implementation SomeBaseClass 

- (NSString *)checkAllProperties 
{ 
    for (property in properties) { 
     // Perform a check on the property 
    } 
} 

EDIT: Byłoby to szczególnie przydatne w niestandardowym - (NSString *)description: ręcznym.

Odpowiedz

21

Aby rozwinąć na odpowiedź mvds' (zacząłem pisać ten przed Widziałem jego), tutaj jest trochę przykładowy program, który korzysta z Objective-C Runtime API pętli i drukowania informacji o każdej nieruchomości w klasie:

#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 

@interface TestClass : NSObject 

@property (nonatomic, retain) NSString *firstName; 
@property (nonatomic, retain) NSString *lastName; 
@property (nonatomic) NSInteger *age; 

@end 

@implementation TestClass 

@synthesize firstName; 
@synthesize lastName; 
@synthesize age; 

@end 

int main(int argc, char *argv[]) { 
    @autoreleasepool { 
     unsigned int numberOfProperties = 0; 
     objc_property_t *propertyArray = class_copyPropertyList([TestClass class], &numberOfProperties); 

     for (NSUInteger i = 0; i < numberOfProperties; i++) 
     { 
      objc_property_t property = propertyArray[i]; 
      NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)]; 
      NSString *attributesString = [[NSString alloc] initWithUTF8String:property_getAttributes(property)]; 
      NSLog(@"Property %@ attributes: %@", name, attributesString); 
     } 
     free(propertyArray); 
    } 
} 

wyjściowe: atrybuty

wiek własności: T^Q, Vage
Property lastName atrybuty: T @ "NSString" &, N, VlastName
Property firstName atrybuty: T @ "NSString", &, N, VfirstName

pamiętać, że program ten musi zostać skompilowany z ARC włączone.

+0

Dobrym pytaniem uzupełniającym byłoby, w jaki sposób dynamicznie zwracać wartości każdego z nich ... Myślę, że dynamicznie utworzę akcesor, ale syntaktycznie, nadal próbuję to rozgryźć. –

+1

Jest kilka sposobów na zrobienie tego, ale najprostszym rozwiązaniem byłoby użycie KVC: 'id value = [self valueForKey: @" propertyName "]'. Trochę się komplikuje, gdy masz zwracane typy zarówno pierwotne (int, float, etc), jak i object (NSString, etc), ale podstawowe założenie będzie działało. –

+0

ten kod wycieka jak w piekle – mvds

14

Zastosowanie

objc_property_t * class_copyPropertyList(Class cls, unsigned int *outCount) 

i czytać https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html o tym, jak to zrobić dokładnie.

Niektóre kodu mogą być ci:

#import <objc/runtime.h> 

unsigned int count=0; 
objc_property_t *props = class_copyPropertyList([self class],&count); 
for (int i=0;i<count;i++) 
{ 
    const char *name = property_getName(props[i]); 
    NSLog(@"property %d: %s",i,name); 
} 
+1

Gwiezdne. Idealne źródło szaleństwa dla bliżej metalu. –

+0

Wielkie dzięki, działa dobrze, w jaki sposób skopiować właściwości jednego obiektu do innych w czasie wykonywania? –

+1

@PavanSaberjack za pomocą 'valueForKey:' i 'setValue: forKey:', gdzie musisz zwrócić uwagę, że 'char * name' nie może być użyte jako obiekt (np. Jako' NSString') bez jakiejś formy konwersji. – mvds

Powiązane problemy