2009-05-06 18 views
19

gelen bu aptal soru olduğuna dair bir his var ama başlatmasını Özel Sınıf NSDictionary

Ben anahtar NSDictionary nesnelerinin bir koleksiyonu var ... Neyse/değer çiftleri Ben özel bir sınıfa karşılık isteyeceğiz ve yaratıldı, MyClass olarak adlandırın. Temelde MyClass ]; için MyClass * instance = [ harita özellikleri gibi bir şey yapmak için kolay veya "en iyi uygulama" yöntemi var mı? NSCoding veya NSKeyedUnarchiver ile bir şeyler yapmam gerektiğini hissettiğime dair bir his var, ancak kendi başıma takılmaya çalışmak yerine, bana doğru yönde işaret edebilecek birilerinin olduğunu düşünüyorum. (Kolaylık olması açısından NSDictionary bir kategori olarak tanımlanır):

cevap

26

-setValu esForKeysWithDictionary: metot, -dictionaryWithValuesForKeys: ile birlikte kullanmak istediğiniz şeydir.

Örnek:

// In your custom class 
+ (id)customClassWithProperties:(NSDictionary *)properties { 
    return [[[self alloc] initWithProperties:properties] autorelease]; 
} 

- (id)initWithProperties:(NSDictionary *)properties { 
    if (self = [self init]) { 
     [self setValuesForKeysWithDictionary:properties]; 
    } 
    return self; 
} 

// ...and to easily derive the dictionary 
NSDictionary *properties = [anObject dictionaryWithValuesForKeys:[anObject allKeys]]; 
+2

Oldukça kullanışlı ve setValuesForPropertiesWithKeys gitmek için bir yoldur. Tam olarak benim kodumun yaptığı şey, ve yerleşiktir! Güzel bul. –

+0

Bu harika bir yöntem. Bunu, objc_ * API ile bağlantılı olarak kullanarak, bir otomatik serileştirme sınıfı oluşturabilirsiniz (böylece hanbersome -initWithCoder: ve -encodeWithCoder: yöntemleri yazmayı durdurabilirsiniz) – retainCount

+0

Awesome. Bu işe yarayacak. –

3

sınıf Key-Value Coding protokole uyan varsayarsak, aşağıdaki kullanabilirsiniz

// myNSDictionaryCategory.h: 
@interface NSDictionary (myCategory) 
- (void)mapPropertiesToObject:(id)instance 
@end 


// myNSDictionaryCategory.m: 
- (void)mapPropertiesToObject:(id)instance 
{ 
    for (NSString * propertyKey in [self allKeys]) 
    { 
     [instance setValue:[self objectForKey:propertyKey] 
        forKey:propertyKey]; 
    } 
} 

Ve burada nasıl sensin kullanmak olacaktır:

#import "myNSDictionaryCategory.h" 
//... 
[someDictionary mapPropertiesToObject:someObject]; 
+0

Yalnızca kod satırlarını değiştirin. Aradığım şey buydu. :) – LucasTizma

+0

Rica ederim! –

+2

Red'in daha iyi bir cevabı var gibi görünüyor. Kabul edilen cevabı onun :) –

6

NSObject üzerinde hiçbir allKeys yoktur. Aşağıdaki gibi NSObject ekstra bir kategori oluşturmak gerekir:

NSObject + PropertyArray.h

@interface NSObject (PropertyArray) 
- (NSArray *) allKeys; 
@end 

NSObject + PropertyArray.m

#import <objc/runtime.h> 

@implementation NSObject (PropertyArray) 
- (NSArray *) allKeys { 
    Class clazz = [self class]; 
    u_int count; 

    objc_property_t* properties = class_copyPropertyList(clazz, &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); 

    return [NSArray arrayWithArray:propertyArray]; 
} 
@end 

Örnek:

#import "NSObject+PropertyArray.h" 

... 

MyObject *obj = [[MyObject alloc] init]; 
obj.a = @"Hello A"; //setting some values to attributes 
obj.b = @"Hello B"; 

//dictionaryWithValuesForKeys requires keys in NSArray. You can now 
//construct such NSArray using `allKeys` from NSObject(PropertyArray) category 
NSDictionary *objDict = [obj dictionaryWithValuesForKeys:[obj allKeys]]; 

//Resurrect MyObject from NSDictionary using setValuesForKeysWithDictionary 
MyObject *objResur = [[MyObject alloc] init]; 
[objResur setValuesForKeysWithDictionary:objDict]; 
+0

Bu kategoride başka bir yöntem de ekleyebilirsiniz: - (NSDictionary *) dictionaryWithValuesForKeys { return [self dictionaryWithValuesForKeys: [self allKeys]]; } – jpalten

0

Eğer böyle bir şey yapma şansınız JSON ile ilgiliyse ve muhtemelen Mantle 012'ye bir göz atmalısınız.https://github.com/Mantle/Mantle

Daha sonra uygun bir yöntem dictionaryValue

[anObject dictionaryValue]; 
0

Sadece (JSON serileştirme sadece kullanarak benim durumumda) özel nesnelerden dictionaryRepresentation almak için NSObject için kategori eklemek alacak:

// NSObject+JSONSerialize.h 
#import <Foundation/Foundation.h> 

@interface NSObject(JSONSerialize) 

- (NSDictionary *)dictionaryRepresentation; 

@end 

// NSObject+JSONSerialize.m 
#import "NSObject+JSONSerialize.h" 
#import <objc/runtime.h> 

@implementation NSObject(JSONSerialize) 

+ (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary { 
    return [[self alloc] initWithDictionary:aDictionary]; 
} 

- (instancetype)initWithDictionary:(NSDictionary *)aDictionary { 
    aDictionary = [aDictionary clean]; 

    self.isReady = NO; 

    for (NSString* propName in [self allPropertyNames]) { 
     [self setValue:aDictionary[propName] forKey:propName]; 
    } 

    //You can add there some custom properties with wrong names like "id" 
    //[self setValue:aDictionary[@"id"] forKeyPath:@"objectID"]; 
    self.isReady = YES; 

    return self; 
} 

- (NSDictionary *)dictionaryRepresentation { 
    NSMutableDictionary *result = [NSMutableDictionary dictionary]; 
    NSArray *propertyNames = [self allPropertyNames]; 

    id object; 
    for (NSString *key in propertyNames) { 
     object = [self valueForKey:key]; 
     if (object) { 
      [result setObject:object forKey:key]; 
     } 
    } 

    return result; 
} 

- (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]; 
    } 
    //You can add there some custom properties with wrong names like "id" 
    //[rv addObject:@"objectID"]; 
    //Example use inside initWithDictionary: 
    //[self setValue:aDictionary[@"id"] forKeyPath:@"objectID"]; 

    free(properties); 

    return rv; 
} 

@end 

Ayrıca, çözümümün iç içe geçmiş nesnelere veya dizilere sahip özel nesnelerle çalışmadığını görebilirsiniz. Diziler için -

if (object) { 
     if ([object isKindOfClass:[NSArray class]]) { 
      @autoreleasepool { 
       NSMutableArray *array = [NSMutableArray array]; 
       for (id item in (NSArray *)object) { 
        [array addObject:[item dictionaryRepresentation]]; 
       } 

       [result setObject:array forKey:key]; 
      } 
     } else { 
      [result setObject:object forKey:key]; 
     } 
    }