Basta aggiungere categoria per NSObject per ottenere dictionaryRepresentation dai vostri oggetti personalizzati (nel mio caso utilizzando in JSON solo serializzazione):
// 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
Inoltre, è possibile vedere che la mia soluzione non funzionerà con oggetti personalizzati con oggetti o matrici annidate. Per gli array, è sufficiente modificare le righe di codice nel metodo dictionaryRepresentation
:
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];
}
}
Questo è piuttosto comodo, e setValuesForPropertiesWithKeys è la strada da percorrere. Fa esattamente quello che fa il mio codice, ed è integrato! Bella scoperta. –
È un metodo meraviglioso. Usandolo in combinazione con l'API objc_ *, puoi creare una classe di serializzazione automatica (così puoi smettere di scrivere quegli ingombranti -initWithCoder: e -encodeWithCoder: metodi) – retainCount
Impressionante. Sarà utile. –