使用以下模型作为示例,在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:...}]}
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中无法使用多态模型吗?
答案 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'