We solved this with 2 minor alterations to JSONModel.m
, introducing a new special JSON property __subclass
which is picked up by the JSONModel
parser and uses the value as the object type. __subclass
is required to be a reserved keyword (therefore no models can use __subclass
as a property name).
Alterations to JSONModel.m
// ...
-(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err
{
// ...
if ([self __isJSONModelSubClass:property.type]) {
//initialize the property's model, store it
JSONModelError* initErr = nil;
-- id value = [[property.type alloc] initWithDictionary: jsonValue error:&initErr];
++ id value;
++ if([jsonValue valueForKey:@"subclass"] != NULL)
++ {
++ Class jsonSubclass = NSClassFromString([d valueForKey:@"subclass"]);
++ if(jsonSubclass)
++ obj = [[jsonSubclass alloc] initWithDictionary:d error:&initErr];
++ }
++ else
++ value = [[property.type alloc] initWithDictionary: jsonValue error:&initErr];
//...
//...
+(NSMutableArray*)arrayOfModelsFromDictionaries:(NSArray*)array error:(NSError**)err
{
// ...
for (NSDictionary* d in array) {
JSONModelError* initErr = nil;
-- id obj = [[self alloc] initWithDictionary:d error:&initErr];
++ id obj;
++ if([d valueForKey:@"subclass"] != NULL)
++ {
++ Class jsonSubclass = NSClassFromString([d valueForKey:@"subclass"]);
++ if(jsonSubclass)
++ obj = [[jsonSubclass alloc] initWithDictionary:d error:&initErr];
++ }
++ else
++ obj = [[self alloc] initWithDictionary:d error:&initErr];
// ...
// ...
NOTE: If the _subclass
'ed JSON model class doesn't exist, then the model will fallback to the superclass.
This will then work with the following models
@interface GameModel : JSONModel
@property (nonatomic, assign) long id;
@property (nonatomic, assign) NSArray<GameEventModel> *events;
@end
@protocol GameEventModel
@end
@interface GameEventModel : JSONModel
@property (nonatomic, assign) long long timestamp;
@end
@interface GameTouchEventModel : GameEventModel
@property (nonatomic, strong) NSArray *point;
@end
When passed the JSON string {id:1, events:[ { __subclass:'GameTouchEventModel', timestamp:1, point: [0,0] } ] }