2014-03-03 27 views
2

使用以下模型作为示例,在JSONModel中处理多态性的最佳实践是什么?JSONModel iOS和多态性

@interface GameModel : JSONModel 
@property (nonatomic, assign) long id; 
@property (nonatomic, assign) NSArray<GameEventModel> *events; 
/* 
    ... 
*/ 
@end 

@interface GameEventModel : JSONModel 
@property (nonatomic, assign) long long timestamp; 
/* 
    ... 
*/ 
@end 

@interface GameTouchEventModel : GameEventModel 
@property (nonatomic, assign) CGPoint point; 
/* 
    ... 
*/ 
@end 

当GameModel用的{id:1, events:[{point:{x:1, y:1}, timestamp:...}]}

JSON字符串开始JSONModel将使用GameEventModel而忽略了point财产。

它会更好用一个通用的GameEventModel含有type财产和财产info ...等

@interface GameTouchEventModel : GameEventModel 
@property (nonatomic, strong) NSString *type; 
@property (nonatomic, strong) NSDictionary *info; 
@end 

,因此模型可以接受JSON作为{id:1, events:[{ type:"GameTouchEventModel", info:{ point:{x:1, y:1}, timestamp:... } }]}

与此问题方法很难读取代码,并且没有编译器警告/错误等。

有没有办法在JSONModel中使用多态模型?

回答

2

我们与2个轻微改动解决了这个给JSONModel.m,导入由所述JSONModel解析器拾起,并使用该值作为对象类型的新的特殊属性JSON __subclass__subclass必须是保留关键字(因此没有模型可以使用__subclass作为属性名称)。

改建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]; 
     // ... 
// ... 

注:如果_subclass“编JSON模型类不存在,那么该模型将回退到超。

这一操作将有如下型号

@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 

工作,当传递JSON字符串{id:1, events:[ { __subclass:'GameTouchEventModel', timestamp:1, point: [0,0] } ] }

0

我觉得BWJSONMatcher可以以非常简洁的方式处理它。

声明模型如下:

@interface GameModel : NSObject<BWJSONValueObject> 
@property (nonatomic, assign) long id; 
@property (nonatomic, strong) NSArray *events; 
@end 

@interface GameEventModel : NSObject 
@property (nonatomic, assign) long long timestamp; 
@end 

@interface GameTouchEventModel : GameEventModel 
@property (nonatomic, strong) NSDictionary *point; 
@end 

GameModel的实现,实现这个功能:

- (Class)typeInProperty:(NSString *)property { 
    if ([property isEqualToString:@"events"]) { 
     return [GameEventModel class]; 
    } 

    return nil; 
} 

然后你可以从JSON字符串一个内让自己的数据实例line:

​​

T他举例说明如何使用BWJSONMatcher来处理多态性,可以找到here

0

TL; DR

使用扬鞭可以帮助,请参阅github这个例子。

关于扬鞭

接受的解决方案是一种方法,但我想提供另一种选择。如果使用Swagger生成模型并利用“allOf/discriminator”特性来实现继承,则生成的Objective-C类将包含与接受的解决方案提供的类似的代码。

YAML

definitions: 
    Point: 
    type: object 
    properties: 
     x: 
     type: number 
     y: 
     type: number 

    GameEventModel: 
    type: object 
    discriminator: gameEventModelType 

    GameTouchEventModel: 
    type: object 
    description: GameTouchEventModel 
    allOf: 
     - $ref: '#/definitions/GameEventModel' 
     - type: object 
     properties: 
      gameEventModelType: 
      type: string 
      point: 
      $ref: '#/definitions/Point' 

    GameFooEventModel: 
    type: object 
    description: GameTouchEventModel 
    allOf: 
     - $ref: '#/definitions/GameEventModel' 
     - type: object 
     properties: 
      gameEventModelType: 
      type: string 
      name: 
      type: string 

    GameModel: 
    type: object 
    properties: 
     id: 
     type: integer 
     format: int64 
     events: 
     type: array 
     items: 
      $ref: '#/definitions/GameEventModel' 

生成代码段

/** 
Maps "discriminator" value to the sub-class name, so that inheritance is supported. 
*/ 
- (id)initWithDictionary:(NSDictionary *)dict error:(NSError *__autoreleasing *)err { 


    NSString * discriminatedClassName = [dict valueForKey:@"gameEventModelType"]; 

    if(discriminatedClassName == nil){ 
     return [super initWithDictionary:dict error:err]; 
    } 

    Class class = NSClassFromString([@"SWG" stringByAppendingString:discriminatedClassName]); 

    if([self class ] == class) { 
     return [super initWithDictionary:dict error:err]; 
    } 


    return [[class alloc] initWithDictionary:dict error: err]; 

}