Skip to content

Instantly share code, notes, and snippets.

@dvdsgl
Created January 17, 2018 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dvdsgl/cf2df4ed93ebf73fb527cd51a217ac15 to your computer and use it in GitHub Desktop.
Save dvdsgl/cf2df4ed93ebf73fb527cd51a217ac15 to your computer and use it in GitHub Desktop.
quicktype Objective-C enum support prototype sample
// 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