JSONModel iOS和多态

时间:2014-03-03 23:13:55

标签: ios json model-view-controller model jsonmodel

使用以下模型作为示例,在JSONModel中处理多态的最佳做法是什么?

@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

使用JSON字符串{id:1, events:[{point:{x:1, y:1}, timestamp:...}]}

启动GameModel时

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中无法使用多态模型吗?

3 个答案:

答案 0 :(得分:2)

我们通过对JSONModel.m的两次小改动解决了这个问题,引入了一个新的特殊JSON属性__subclass,它由JSONModel解析器拾取并使用该值作为对象类型。 __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'ed 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] } ] }

答案 1 :(得分: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字符串中获取自己的数据实例:

GameModel *gameModel = [GameModel fromJSONString:jsonString];

可以找到有关如何使用 BWJSONMatcher 处理多态的示例here

答案 2 :(得分:0)

<强> TL; DR

使用Swagger可以提供帮助,请参阅github中的此示例。

关于Swagger

接受的解决方案是单向的,但我想提供替代方案。如果使用Swagger生成模型并利用&#34; allOf / discriminator&#34;实现继承的功能,生成的Objective-C类将包含与接受的解决方案提供的代码类似的代码。

Yaml

<div id="admin">
<%= calendar do |date| %>
    <%= date.day %><br>
        <%  @resv_by_date.each do |reservation| %>
        <%= reservation.requested_date.to_date  %><br>
    <% end %>
<% end %>
</div>

生成的代码段

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'