Created
January 17, 2018 06:56
-
-
Save dvdsgl/cf2df4ed93ebf73fb527cd51a217ac15 to your computer and use it in GitHub Desktop.
quicktype Objective-C enum support prototype sample
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To parse this JSON: | |
// | |
// NSError *error; | |
// QTPokedex *pokedex = [QTPokedex fromJSON:json encoding:NSUTF8Encoding error:&error] | |
#import <Foundation/Foundation.h> | |
// MARK: Types | |
typedef NSNumber NSBoolean; | |
@class QTPokedex; | |
@class QTPokemon; | |
@class QTEvolution; | |
typedef NS_ENUM(NSInteger, QTEgg) { | |
QTNotInEggsEgg, | |
QTOmanyteCandyEgg, | |
QTThe10KMEgg, | |
QTThe2KMEgg, | |
QTThe5KMEgg, | |
}; | |
typedef NS_ENUM(NSInteger, QTWeakness) { | |
QTBugWeakness, | |
QTDarkWeakness, | |
QTDragonWeakness, | |
QTElectricWeakness, | |
QTFairyWeakness, | |
QTFightingWeakness, | |
QTFireWeakness, | |
QTFlyingWeakness, | |
QTGhostWeakness, | |
QTGrassWeakness, | |
QTGroundWeakness, | |
QTIceWeakness, | |
QTPoisonWeakness, | |
QTPsychicWeakness, | |
QTRockWeakness, | |
QTSteelWeakness, | |
QTWaterWeakness, | |
}; | |
NS_ASSUME_NONNULL_BEGIN | |
NSUInteger readEnum(NSString *value, char *_Nonnull *_Nonnull values) { | |
const char *utf8Value = [value UTF8String]; | |
int len = sizeof(values) / sizeof(values[0]); | |
for (int i = 0; i < len; i++) { | |
if (strcmp(values[i], utf8Value) == 0) return i; | |
} | |
@throw [NSException exceptionWithName:@"EnumException" | |
reason:@"Out of range" | |
userInfo:@{ @"value":value }]; | |
} | |
// MARK: Top-level marshalling functions | |
QTPokedex *QTPokedexFromData(NSData *data, NSError **error); | |
QTPokedex *QTPokedexFromJSON(NSString *json, NSStringEncoding encoding, NSError **error); | |
NSData *QTPokedexToData(QTPokedex *pokedex, NSError **error); | |
NSString *QTPokedexToJSON(QTPokedex *pokedex, NSStringEncoding encoding, NSError **error); | |
@interface QTPokedex : NSObject | |
@property (nonatomic, copy) NSArray<QTPokemon *> *pokemon; | |
+ (_Nullable instancetype)fromJSON:(NSString *)json; | |
+ (_Nullable instancetype)fromJSON:(NSString *)json encoding:(NSStringEncoding)encoding error:(NSError *_Nullable *)error; | |
+ (_Nullable instancetype)fromData:(NSData *)data error:(NSError *_Nullable *)error; | |
- (NSString *_Nullable)toJSON; | |
- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error; | |
- (NSData *_Nullable)toData:(NSError *_Nullable *)error; | |
@end | |
@interface QTPokemon : NSObject | |
@property (nonatomic, copy) NSNumber *id; | |
@property (nonatomic, copy) NSString *num; | |
@property (nonatomic, copy) NSString *name; | |
@property (nonatomic, copy) NSString *img; | |
@property (nonatomic, copy) NSArray<NSString *> *type; | |
@property (nonatomic, copy) NSString *height; | |
@property (nonatomic, copy) NSString *weight; | |
@property (nonatomic, copy) NSString *candy; | |
@property (nonatomic, copy, nullable) NSNumber *candyCount; | |
@property (nonatomic, assign) QTEgg egg; | |
@property (nonatomic, copy) NSNumber *spawnChance; | |
@property (nonatomic, copy) NSNumber *avgSpawns; | |
@property (nonatomic, copy) NSString *spawnTime; | |
@property (nonatomic, copy, nullable) NSArray<NSNumber *> *multipliers; | |
@property (nonatomic, copy) NSArray<QTWeakness> *weaknesses; | |
@property (nonatomic, copy, nullable) NSArray<QTEvolution *> *nextEvolution; | |
@property (nonatomic, copy, nullable) NSArray<QTEvolution *> *prevEvolution; | |
@end | |
@interface QTEvolution : NSObject | |
@property (nonatomic, copy) NSString *num; | |
@property (nonatomic, copy) NSString *name; | |
@end | |
NS_ASSUME_NONNULL_END | |
// MARK: Implementation | |
#define λ(decl, expr) (^(decl) { return (expr); }) | |
#define NSNullify(x) ([x isNotEqualTo:[NSNull null]] ? x : [NSNull null]) | |
NS_ASSUME_NONNULL_BEGIN | |
char* _Nonnull _QTEggStrings[] = { | |
"Not in Eggs", | |
"Omanyte Candy", | |
"10 km", | |
"2 km", | |
"5 km", | |
}; | |
char* _Nonnull _QTWeaknessStrings[] = { | |
"Bug", | |
"Dark", | |
"Dragon", | |
"Electric", | |
"Fairy", | |
"Fighting", | |
"Fire", | |
"Flying", | |
"Ghost", | |
"Grass", | |
"Ground", | |
"Ice", | |
"Poison", | |
"Psychic", | |
"Rock", | |
"Steel", | |
"Water", | |
}; | |
@implementation NSArray (JSONConversion) | |
- (NSArray *)map:(id (^)(id element))f { | |
id result = [NSMutableArray arrayWithCapacity:self.count]; | |
for (id x in self) [result addObject:f(x)]; | |
return result; | |
} | |
@end | |
@implementation NSDictionary (JSONConversion) | |
- (NSDictionary *)map:(id (^)(id value))f { | |
id result = [NSMutableDictionary dictionaryWithCapacity:self.count]; | |
for (id key in self) [result setObject:f([self objectForKey:key]) forKey:key]; | |
return result; | |
} | |
- (NSException *)exceptionForKey:(id)key type:(NSString *)type { | |
return [NSException exceptionWithName:@"TypeException" | |
reason:[NSString stringWithFormat:@"Expected a %@", type] | |
userInfo:@{ @"dictionary":self, @"key":key }]; | |
} | |
- (id)objectForKey:(NSString *)key withClass:(Class)cls { | |
id value = [self objectForKey:key]; | |
if ([value isKindOfClass:cls]) return value; | |
else @throw [self exceptionForKey:key type:NSStringFromClass(cls)]; | |
} | |
- (NSBoolean *)boolForKey:(NSString *)key { | |
id value = [self objectForKey:key]; | |
if ([value isEqual:@(YES)] || [value isEqual:@(NO)]) return value; | |
else @throw [self exceptionForKey:key type:@"bool"]; | |
} | |
@end | |
@interface QTPokedex (JSONConversion) | |
+ (instancetype)fromJSONDictionary:(NSDictionary *)dict; | |
- (NSDictionary *)JSONDictionary; | |
@end | |
@interface QTPokemon (JSONConversion) | |
+ (instancetype)fromJSONDictionary:(NSDictionary *)dict; | |
- (NSDictionary *)JSONDictionary; | |
@end | |
@interface QTEvolution (JSONConversion) | |
+ (instancetype)fromJSONDictionary:(NSDictionary *)dict; | |
- (NSDictionary *)JSONDictionary; | |
@end | |
// MARK: JSON serialization implementations | |
QTPokedex *QTPokedexFromData(NSData *data, NSError **error) { | |
NSDictionary<NSString *, id> *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:error]; | |
return *error ? nil : [QTPokedex fromJSONDictionary:json]; | |
} | |
QTPokedex *QTPokedexFromJSON(NSString *json, NSStringEncoding encoding, NSError **error) { | |
return QTPokedexFromData([json dataUsingEncoding:encoding], error); | |
} | |
NSData *QTPokedexToData(QTPokedex *pokedex, NSError **error) { | |
NSDictionary<NSString *, id> *json = [pokedex JSONDictionary]; | |
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:kNilOptions error:error]; | |
return *error ? nil : data; | |
} | |
NSString *QTPokedexToJSON(QTPokedex *pokedex, NSStringEncoding encoding, NSError **error) { | |
NSData *data = QTPokedexToData(pokedex, error); | |
return data ? [[NSString alloc] initWithData:data encoding:encoding] : nil; | |
} | |
@implementation QTPokedex | |
@synthesize pokemon; | |
+ (_Nullable instancetype)fromData:(NSData *)data error:(NSError *_Nullable *)error { | |
return QTPokedexFromData(data, error); | |
} | |
+ (_Nullable instancetype)fromJSON:(NSString *)json encoding:(NSStringEncoding)encoding error:(NSError *_Nullable *)error; { | |
return QTPokedexFromJSON(json, encoding, error); | |
} | |
+ (_Nullable instancetype)fromJSON:(NSString *)json { | |
NSError *error; | |
return QTPokedexFromJSON(json, NSUTF8StringEncoding, &error); | |
} | |
+ (instancetype)fromJSONDictionary:(NSDictionary *)dict { | |
return [[QTPokedex alloc] initWithJSONDictionary:dict]; | |
} | |
- (instancetype)initWithJSONDictionary:(NSDictionary *)dict { | |
if (self = [super init]) { | |
pokemon = [[dict objectForKey:@"pokemon" withClass:[NSArray class]] map:λ(id x, [QTPokemon fromJSONDictionary:x])]; | |
} | |
return self; | |
} | |
- (NSDictionary *)JSONDictionary { | |
return @{ | |
@"pokemon": [pokemon map:λ(id x, [x JSONDictionary])], | |
}; | |
} | |
- (NSData *_Nullable)toData:(NSError *_Nullable *)error { | |
return QTPokedexToData(self, error); | |
} | |
- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error { | |
return QTPokedexToJSON(self, encoding, error); | |
} | |
- (NSString *_Nullable)toJSON { | |
NSError *error; | |
return QTPokedexToJSON(self, NSUTF8StringEncoding, &error); | |
} | |
@end | |
@implementation QTPokemon | |
@synthesize id, num, name, img, type; | |
@synthesize height, weight, candy, candyCount, egg; | |
@synthesize spawnChance, avgSpawns, spawnTime, multipliers, weaknesses; | |
@synthesize nextEvolution, prevEvolution; | |
+ (instancetype)fromJSONDictionary:(NSDictionary *)dict { | |
return [[QTPokemon alloc] initWithJSONDictionary:dict]; | |
} | |
- (instancetype)initWithJSONDictionary:(NSDictionary *)dict { | |
if (self = [super init]) { | |
self.id = [dict objectForKey:@"id" withClass:[NSNumber class]]; | |
num = [dict objectForKey:@"num" withClass:[NSString class]]; | |
name = [dict objectForKey:@"name" withClass:[NSString class]]; | |
img = [dict objectForKey:@"img" withClass:[NSString class]]; | |
type = [[dict objectForKey:@"type" withClass:[NSArray class]] map:λ(id x, x)]; | |
height = [dict objectForKey:@"height" withClass:[NSString class]]; | |
weight = [dict objectForKey:@"weight" withClass:[NSString class]]; | |
candy = [dict objectForKey:@"candy" withClass:[NSString class]]; | |
if ([[dict objectForKey:@"candy_count"] isNotEqualTo:[NSNull null]]) { | |
candyCount = [dict objectForKey:@"candy_count" withClass:[NSNumber class]]; | |
} | |
egg = readEnum([dict objectForKey:@"egg" withClass:[NSString class]], _QTEggStrings); | |
spawnChance = [dict objectForKey:@"spawn_chance" withClass:[NSNumber class]]; | |
avgSpawns = [dict objectForKey:@"avg_spawns" withClass:[NSNumber class]]; | |
spawnTime = [dict objectForKey:@"spawn_time" withClass:[NSString class]]; | |
if ([[dict objectForKey:@"multipliers"] isNotEqualTo:[NSNull null]]) { | |
multipliers = [[dict objectForKey:@"multipliers" withClass:[NSArray class]] map:λ(id x, x)]; | |
} | |
weaknesses = [[dict objectForKey:@"weaknesses" withClass:[NSArray class]] map:λ(id x, readEnum(x, _QTWeaknessStrings))]; | |
if ([[dict objectForKey:@"next_evolution"] isNotEqualTo:[NSNull null]]) { | |
nextEvolution = [[dict objectForKey:@"next_evolution" withClass:[NSArray class]] map:λ(id x, [QTEvolution fromJSONDictionary:x])]; | |
} | |
if ([[dict objectForKey:@"prev_evolution"] isNotEqualTo:[NSNull null]]) { | |
prevEvolution = [[dict objectForKey:@"prev_evolution" withClass:[NSArray class]] map:λ(id x, [QTEvolution fromJSONDictionary:x])]; | |
} | |
} | |
return self; | |
} | |
- (NSDictionary *)JSONDictionary { | |
return @{ | |
@"id": self.id, | |
@"num": num, | |
@"name": name, | |
@"img": img, | |
@"type": type, | |
@"height": height, | |
@"weight": weight, | |
@"candy": candy, | |
@"candy_count": NSNullify(candyCount), | |
@"egg": [NSString stringWithUTF8String:_QTEggStrings[egg]], | |
@"spawn_chance": spawnChance, | |
@"avg_spawns": avgSpawns, | |
@"spawn_time": spawnTime, | |
@"multipliers": NSNullify(multipliers), | |
@"weaknesses": weaknesses, | |
@"next_evolution": NSNullify([nextEvolution map:λ(id x, [x JSONDictionary])]), | |
@"prev_evolution": NSNullify([prevEvolution map:λ(id x, [x JSONDictionary])]), | |
}; | |
} | |
@end | |
@implementation QTEvolution | |
@synthesize num, name; | |
+ (instancetype)fromJSONDictionary:(NSDictionary *)dict { | |
return [[QTEvolution alloc] initWithJSONDictionary:dict]; | |
} | |
- (instancetype)initWithJSONDictionary:(NSDictionary *)dict { | |
if (self = [super init]) { | |
num = [dict objectForKey:@"num" withClass:[NSString class]]; | |
name = [dict objectForKey:@"name" withClass:[NSString class]]; | |
} | |
return self; | |
} | |
- (NSDictionary *)JSONDictionary { | |
return @{ | |
@"num": num, | |
@"name": name, | |
}; | |
} | |
@end | |
NS_ASSUME_NONNULL_END |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment