-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding tons of introspection code to parse attributes.
- Loading branch information
Showing
10 changed files
with
291 additions
and
5 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// | ||
// BDKUntappdCheckin.h | ||
// | ||
// Created by Ben Kreeger on 3/4/14. | ||
// Copyright (c) 2014 Ben Kreeger. All rights reserved. | ||
// | ||
|
||
#import "BDKUntappdModel.h" | ||
|
||
@interface BDKUntappdCheckin : BDKUntappdModel | ||
|
||
@property (strong, nonatomic) NSArray *badges; | ||
@property (strong, nonatomic) NSDictionary *beer; | ||
@property (strong, nonatomic) NSDictionary *brewery; | ||
@property (strong, nonatomic) NSArray *comments; | ||
@property (strong, nonatomic) NSDate *createdAt; | ||
@property (strong, nonatomic) NSArray *media; | ||
@property (strong, nonatomic) NSNumber *ratingScore; | ||
@property (strong, nonatomic) NSDictionary *source; | ||
@property (strong, nonatomic) NSArray *toasts; | ||
@property (strong, nonatomic) NSDictionary *user; | ||
@property (strong, nonatomic) NSDictionary *venue; | ||
|
||
@end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// | ||
// BDKUntappdCheckin.h | ||
// | ||
// Created by Ben Kreeger on 3/4/14. | ||
// Copyright (c) 2014 Ben Kreeger. All rights reserved. | ||
// | ||
|
||
#import "BDKUntappdCheckin.h" | ||
|
||
@implementation BDKUntappdCheckin | ||
|
||
#pragma mark - BDKUntappdModel | ||
|
||
- (NSString *)remoteIdentifierName { | ||
return @"checkin_id"; | ||
} | ||
|
||
@end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// | ||
// BDKUntappdModel.h | ||
// | ||
// Created by Ben Kreeger on 3/4/14. | ||
// Copyright (c) 2014 Ben Kreeger. All rights reserved. | ||
// | ||
|
||
@interface BDKUntappdModel : NSObject <NSCoding> | ||
|
||
@property (strong, nonatomic) NSString *identifier; | ||
@property (readonly, strong, nonatomic) NSString *remoteIdentifierName; | ||
|
||
+ (instancetype)modelWithDictionary:(NSDictionary *)dictionary; | ||
- (instancetype)initWithDictionary:(NSDictionary *)dictionary; | ||
- (void)updateWithDictionary:(NSDictionary *)dictionary; | ||
|
||
@end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
// | ||
// BDKUntappdModel.m | ||
// | ||
// Created by Ben Kreeger on 3/4/14. | ||
// Copyright (c) 2014 Ben Kreeger. All rights reserved. | ||
// | ||
|
||
#import "BDKUntappdModel.h" | ||
|
||
#import "NSObject+BDKUntappd.h" | ||
|
||
#import <TransformerKit/TransformerKit.h> | ||
#import <TransformerKit/NSValueTransformer+TransformerKit.h> | ||
#import <objc/runtime.h> | ||
|
||
// Praise be to Jastor. https://github.com/elado/jastor | ||
static const char *property_getTypeName(objc_property_t property) { | ||
const char *attributes = property_getAttributes(property); | ||
char buffer[1 + strlen(attributes)]; | ||
strcpy(buffer, attributes); | ||
char *state = buffer, *attribute; | ||
while ((attribute = strsep(&state, ",")) != NULL) { | ||
if (attribute[0] == 'T') { | ||
size_t len = strlen(attribute); | ||
attribute[len - 1] = '\0'; | ||
return (const char *)[[NSData dataWithBytes:(attribute + 3) length:len - 2] bytes]; | ||
} | ||
} | ||
return "@"; | ||
} | ||
|
||
@implementation BDKUntappdModel | ||
|
||
+ (instancetype)modelWithDictionary:(NSDictionary *)dictionary { | ||
return [[self alloc] initWithDictionary:dictionary]; | ||
} | ||
|
||
- (instancetype)initWithDictionary:(NSDictionary *)dictionary { | ||
self = [super init]; | ||
if (!self) return nil; | ||
[self updateWithDictionary:dictionary]; | ||
return self; | ||
} | ||
|
||
- (void)updateWithDictionary:(NSDictionary *)dictionary { | ||
NSArray *properties = [[self class] propertyNamesForClass:[self class]]; | ||
[properties enumerateObjectsUsingBlock:^(NSString *propertyName, NSUInteger idx, BOOL *stop) { | ||
NSString *remoteName = [[self class] remotePropertyNameForLocalPropertyName:propertyName]; | ||
id val = dictionary[remoteName]; | ||
if (![val bdk_isPresent]) return; | ||
if ([[self class] property:propertyName isReadOnlyForClass:[self class]]) return; | ||
|
||
if ([val isKindOfClass:[NSDictionary class]]) { | ||
// Untappd's API has arrays nested in dictionaries with some metadata; this pulls it out and rights it. | ||
if (val[@"items"]) { | ||
val = val[@"items"]; | ||
} else { | ||
Class klass = [[self class] classForPropertyName:propertyName inClass:[self class]]; | ||
val = [[klass alloc] initWithDictionary:val]; | ||
} | ||
|
||
} | ||
|
||
if ([val isKindOfClass:[NSArray class]]) { | ||
NSArray *valuesForVal = (NSArray *)val; | ||
NSMutableArray *objects = [NSMutableArray arrayWithCapacity:[valuesForVal count]]; | ||
[valuesForVal enumerateObjectsUsingBlock:^(id subVal, NSUInteger idx, BOOL *stop) { | ||
if ([[subVal class] isSubclassOfClass:[NSDictionary class]]) { | ||
SEL classSelector = NSSelectorFromString([NSString stringWithFormat:@"%@_class", propertyName]); | ||
if ([[self class] respondsToSelector:classSelector]) { | ||
Class klass = [[self class] performSelector:classSelector]; | ||
if ([klass isSubclassOfClass:[BDKUntappdModel class]]) { | ||
BDKUntappdModel *model = [[klass alloc] initWithDictionary:subVal]; | ||
[objects addObject:model]; | ||
return; | ||
} | ||
} | ||
[objects addObject:subVal]; | ||
} | ||
}]; | ||
val = [objects copy]; | ||
|
||
} | ||
|
||
[self setValue:val forKey:propertyName]; | ||
}]; | ||
|
||
id identifierValue = [dictionary objectForKey:self.remoteIdentifierName]; | ||
if ([identifierValue bdk_isPresent]) { | ||
if (![identifierValue isKindOfClass:[NSString class]]) { | ||
identifierValue = [NSString stringWithFormat:@"%@", identifierValue]; | ||
} | ||
[self setValue:identifierValue forKey:@"identifier"]; | ||
} | ||
} | ||
|
||
- (void)dealloc { | ||
self.identifier = nil; | ||
} | ||
|
||
- (NSString *)description { | ||
return [NSString stringWithFormat:@"<%@ %p> { id: %@ }", NSStringFromClass([self class]), self, self.identifier]; | ||
} | ||
|
||
#pragma mark - Properties | ||
|
||
- (NSString *)remoteIdentifierName { | ||
return @"id"; | ||
} | ||
|
||
#pragma mark - NSCoding | ||
|
||
- (instancetype)initWithCoder:(NSCoder *)aDecoder { | ||
self = [super init]; | ||
if (!self) return nil; | ||
|
||
id decoded = [aDecoder decodeObjectForKey:@"identifier"]; | ||
[self setValue:decoded forKey:@"identifier"]; | ||
|
||
NSArray *propertyNames = [[self class] propertyNamesForClass:[self class]]; | ||
[propertyNames enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) { | ||
if ([[self class] property:key isReadOnlyForClass:[self class]]) return; | ||
id decoded = [aDecoder decodeObjectForKey:key]; | ||
if (![decoded bdk_isPresent]) return; | ||
[self setValue:decoded forKey:key]; | ||
}]; | ||
return self; | ||
} | ||
|
||
- (void)encodeWithCoder:(NSCoder *)aCoder { | ||
[aCoder encodeObject:self.identifier forKey:@"identifier"]; | ||
NSArray *propertyNames = [[self class] propertyNamesForClass:[self class]]; | ||
[propertyNames enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) { | ||
[aCoder encodeObject:[self valueForKey:key] forKey:key]; | ||
}]; | ||
} | ||
|
||
#pragma mark - Private methods | ||
|
||
+ (NSArray *)propertyNamesForClass:(Class)klass { | ||
if (klass == [BDKUntappdModel class]) { | ||
return [NSArray array]; | ||
} | ||
|
||
int numberOfProperties = 0; | ||
objc_property_t *propertyTypes = class_copyPropertyList(klass, &numberOfProperties); | ||
|
||
NSMutableArray *propertyList = [NSMutableArray arrayWithCapacity:numberOfProperties]; | ||
for (int idx = 0; idx < numberOfProperties; idx++) { | ||
objc_property_t property = propertyTypes[idx]; | ||
[propertyList addObject:[NSString stringWithUTF8String:property_getName(property)]]; | ||
} | ||
|
||
free(propertyTypes); | ||
return propertyList; | ||
} | ||
|
||
+ (NSString *)remotePropertyNameForLocalPropertyName:(NSString *)localPropertyName { | ||
NSString *unLlamad = [[NSValueTransformer valueTransformerForName:TTTLlamaCaseStringTransformerName] | ||
reverseTransformedValue:localPropertyName]; | ||
return [[NSValueTransformer valueTransformerForName:TTTTrainCaseStringTransformerName] transformedValue:unLlamad]; | ||
} | ||
|
||
+ (BOOL)property:(NSString *)propertyName isReadOnlyForClass:(Class)klass { | ||
const char *type = property_getAttributes(class_getProperty(klass, [propertyName UTF8String])); | ||
NSString *typeAttribute = [[[NSString stringWithUTF8String:type] componentsSeparatedByString:@","] objectAtIndex:1]; | ||
return [typeAttribute rangeOfString:@"R"].length > 0; | ||
} | ||
|
||
+ (Class)classForPropertyName:(NSString *)propertyName inClass:(Class)klass { | ||
int numberOfProperties = 0; | ||
objc_property_t *propertyTypes = class_copyPropertyList(klass, &numberOfProperties); | ||
const char *cPropertyName = [propertyName UTF8String]; | ||
|
||
for (int idx = 0; idx < numberOfProperties; idx++) { | ||
objc_property_t property = propertyTypes[idx]; | ||
if (strcmp(cPropertyName, property_getName(property)) == 0) { | ||
free(propertyTypes); | ||
return NSClassFromString([NSString stringWithUTF8String:property_getTypeName(property)]); | ||
} | ||
} | ||
|
||
free(propertyTypes); | ||
return [self classForPropertyName:propertyName inClass:class_getSuperclass(klass)]; | ||
} | ||
|
||
@end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#import "BDKUntappdModel.h" | ||
#import "BDKUntappdCheckin.h" |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// | ||
// NSObject+BDKUntappd.h | ||
// | ||
// Created by Ben Kreeger on 3/5/14. | ||
// Copyright (c) 2014 Ben Kreeger. All rights reserved. | ||
// | ||
|
||
@interface NSObject (BDKUntappd) | ||
|
||
- (BOOL)bdk_isPresent; | ||
|
||
@end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// | ||
// NSObject+BDKUntappd.m | ||
// | ||
// Created by Ben Kreeger on 3/5/14. | ||
// Copyright (c) 2014 Ben Kreeger. All rights reserved. | ||
// | ||
|
||
#import "NSObject+BDKUntappd.h" | ||
|
||
@implementation NSObject (BDKUntappd) | ||
|
||
- (BOOL)bdk_isPresent { | ||
return ![self isEqual:[NSNull null]]; | ||
} | ||
|
||
@end |
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