2014-03-03 35 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]; 

}