Switching to NSInvocation approach to dynamic JSON library-agnostic encoding and decoding, appropriating @steipete's work on HockeyApp
This commit is contained in:
parent
9a91afe3e2
commit
206f6ff1f6
3 changed files with 113 additions and 63 deletions
|
|
@ -24,69 +24,123 @@
|
||||||
|
|
||||||
#include <Availability.h>
|
#include <Availability.h>
|
||||||
|
|
||||||
#if defined(_AF_USE_JSONKIT)
|
|
||||||
#import "JSONKit.h"
|
|
||||||
#elif defined(_AF_USE_SBJSON)
|
|
||||||
#import "SBJSON.h"
|
|
||||||
|
|
||||||
static SBJsonParser * _SBJSONParser() {
|
|
||||||
static SBJsonParser *_af_SBJSONParser = nil;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
_af_SBJSONParser = [[SBJsonParser alloc] init];
|
|
||||||
});
|
|
||||||
|
|
||||||
return _af_SBJSONParser;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SBJsonWriter * _SBJSONWriter() {
|
|
||||||
static SBJsonWriter *_af_SBJSONWriter = nil;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
_af_SBJSONWriter = [[SBJsonWriter alloc] init];
|
|
||||||
});
|
|
||||||
|
|
||||||
return _af_SBJSONWriter;
|
|
||||||
}
|
|
||||||
#elif defined(_AF_USE_YAJL)
|
|
||||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
|
||||||
#import <YAJL/YAJL.h>
|
|
||||||
#elif __MAC_OS_X_VERSION_MIN_REQUIRED
|
|
||||||
#import <YAJLiOS/YAJL.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline NSData * AFJSONEncode(id object, NSError **error) {
|
static inline NSData * AFJSONEncode(id object, NSError **error) {
|
||||||
#if defined(_AF_USE_JSONKIT)
|
NSData *data = nil;
|
||||||
return [object JSONData];
|
|
||||||
#elif defined(_AF_USE_SBJSON)
|
|
||||||
SBJsonWriter *writer = _SBJSONWriter();
|
|
||||||
return [writer dataWithObject:object];
|
|
||||||
#elif defined(_AF_USE_YAJL)
|
|
||||||
return [[object yajl_JSONString] dataUsingEncoding:NSUTF8StringEncoding]];
|
|
||||||
#else
|
|
||||||
if ([NSJSONSerialization class]) {
|
|
||||||
return [NSJSONSerialization dataWithJSONObject:object options:0 error:error];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return nil;
|
id _NSJSONSerializationClass = NSClassFromString(@"NSJSONSerialization");
|
||||||
|
SEL _NSJSONSerializationSelector = NSSelectorFromString(@"dataWithJSONObject:options:error:");
|
||||||
|
SEL _JSONKitSelector = NSSelectorFromString(@"JSONDataWithOptions:error:");
|
||||||
|
SEL _SBJSONSelector = NSSelectorFromString(@"JSONRepresentation");
|
||||||
|
SEL _YAJLSelector = NSSelectorFromString(@"yajl_JSONString");
|
||||||
|
|
||||||
|
if (_NSJSONSerializationClass && [_NSJSONSerializationClass respondsToSelector:_NSJSONSerializationSelector]) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[_NSJSONSerializationClass methodSignatureForSelector:_NSJSONSerializationSelector]];
|
||||||
|
invocation.target = _NSJSONSerializationClass;
|
||||||
|
invocation.selector = _NSJSONSerializationSelector;
|
||||||
|
|
||||||
|
[invocation setArgument:&object atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
|
||||||
|
NSUInteger writeOptions = 0;
|
||||||
|
[invocation setArgument:&writeOptions atIndex:3];
|
||||||
|
[invocation setArgument:error atIndex:4];
|
||||||
|
|
||||||
|
[invocation invoke];
|
||||||
|
[invocation getReturnValue:&data];
|
||||||
|
} else if (_JSONKitSelector && [data respondsToSelector:_JSONKitSelector]) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[data methodSignatureForSelector:_JSONKitSelector]];
|
||||||
|
invocation.target = data;
|
||||||
|
invocation.selector = _JSONKitSelector;
|
||||||
|
|
||||||
|
NSUInteger serializeOptionFlags = 0;
|
||||||
|
[invocation setArgument:&serializeOptionFlags atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
|
||||||
|
[invocation setArgument:error atIndex:3];
|
||||||
|
|
||||||
|
[invocation invoke];
|
||||||
|
[invocation getReturnValue:&data];
|
||||||
|
} else if (_SBJSONSelector && [data respondsToSelector:_SBJSONSelector]) {
|
||||||
|
NSString *JSONString = nil;
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[data methodSignatureForSelector:_SBJSONSelector]];
|
||||||
|
invocation.target = data;
|
||||||
|
invocation.selector = _SBJSONSelector;
|
||||||
|
|
||||||
|
[invocation invoke];
|
||||||
|
[invocation getReturnValue:&data];
|
||||||
|
|
||||||
|
data = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
} else if (_YAJLSelector && [data respondsToSelector:_YAJLSelector]) {
|
||||||
|
@try {
|
||||||
|
NSString *JSONString = nil;
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[data methodSignatureForSelector:_YAJLSelector]];
|
||||||
|
invocation.target = data;
|
||||||
|
invocation.selector = _YAJLSelector;
|
||||||
|
|
||||||
|
[invocation invoke];
|
||||||
|
[invocation getReturnValue:&JSONString];
|
||||||
|
|
||||||
|
data = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
}
|
||||||
|
@catch (NSException *exception) {
|
||||||
|
*error = [[[NSError alloc] initWithDomain:NSStringFromClass([exception class]) code:0 userInfo:[exception userInfo]] autorelease];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline id AFJSONDecode(NSData *data, NSError **error) {
|
static inline id AFJSONDecode(NSData *data, NSError **error) {
|
||||||
|
id JSON = nil;
|
||||||
|
|
||||||
#if defined(_AF_USE_JSONKIT)
|
id _NSJSONSerializationClass = NSClassFromString(@"NSJSONSerialization");
|
||||||
return [[JSONDecoder decoder] objectWithData:data error:error];
|
SEL _NSJSONSerializationSelector = NSSelectorFromString(@"JSONObjectWithData:options:error:");
|
||||||
#elif defined(_AF_USE_SBJSON)
|
SEL _JSONKitSelector = NSSelectorFromString(@"objectFromJSONDataWithParseOptions:error:");
|
||||||
SBJsonParser *parser = _SBJsonParser();
|
SEL _SBJSONSelector = NSSelectorFromString(@"JSONValue");
|
||||||
return [parser objectWithData:data];
|
SEL _YAJLSelector = NSSelectorFromString(@"yajl_JSONWithOptions:error:");
|
||||||
#elif defined(_AF_USE_YAJL)
|
|
||||||
return [data yajl_JSON];
|
if (_NSJSONSerializationClass && [_NSJSONSerializationClass respondsToSelector:_NSJSONSerializationSelector]) {
|
||||||
#else
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[_NSJSONSerializationClass methodSignatureForSelector:_NSJSONSerializationSelector]];
|
||||||
if ([NSJSONSerialization class]) {
|
invocation.target = _NSJSONSerializationClass;
|
||||||
return [NSJSONSerialization JSONObjectWithData:data options:0 error:error];
|
invocation.selector = _NSJSONSerializationSelector;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return nil;
|
[invocation setArgument:&data atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
|
||||||
|
NSUInteger readOptions = 0;
|
||||||
|
[invocation setArgument:&readOptions atIndex:3];
|
||||||
|
[invocation setArgument:error atIndex:4];
|
||||||
|
|
||||||
|
[invocation invoke];
|
||||||
|
[invocation getReturnValue:&JSON];
|
||||||
|
} else if (_JSONKitSelector && [data respondsToSelector:_JSONKitSelector]) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[data methodSignatureForSelector:_JSONKitSelector]];
|
||||||
|
invocation.target = data;
|
||||||
|
invocation.selector = _JSONKitSelector;
|
||||||
|
|
||||||
|
NSUInteger parseOptionFlags = 0;
|
||||||
|
[invocation setArgument:&parseOptionFlags atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
|
||||||
|
[invocation setArgument:error atIndex:3];
|
||||||
|
|
||||||
|
[invocation invoke];
|
||||||
|
[invocation getReturnValue:&JSON];
|
||||||
|
} else if (_SBJSONSelector && [data respondsToSelector:_SBJSONSelector]) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[data methodSignatureForSelector:_SBJSONSelector]];
|
||||||
|
invocation.target = data;
|
||||||
|
invocation.selector = _SBJSONSelector;
|
||||||
|
|
||||||
|
[invocation invoke];
|
||||||
|
[invocation getReturnValue:&JSON];
|
||||||
|
} else if (_YAJLSelector && [data respondsToSelector:_YAJLSelector]) {
|
||||||
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[data methodSignatureForSelector:_YAJLSelector]];
|
||||||
|
invocation.target = data;
|
||||||
|
invocation.selector = _YAJLSelector;
|
||||||
|
|
||||||
|
NSUInteger yajlParserOptions = 0;
|
||||||
|
[invocation setArgument:&yajlParserOptions atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
|
||||||
|
[invocation setArgument:error atIndex:3];
|
||||||
|
|
||||||
|
[invocation invoke];
|
||||||
|
[invocation getReturnValue:&JSON];
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "AFHTTPClient.h"
|
#import "AFHTTPClient.h"
|
||||||
|
|
||||||
#define _AF_USE_JSONKIT
|
|
||||||
|
|
||||||
extern NSString * const kAFGowallaClientID;
|
extern NSString * const kAFGowallaClientID;
|
||||||
extern NSString * const kAFGowallaBaseURLString;
|
extern NSString * const kAFGowallaBaseURLString;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "AFHTTPClient.h"
|
#import "AFHTTPClient.h"
|
||||||
|
|
||||||
#define _AF_USE_JSONKIT
|
|
||||||
|
|
||||||
extern NSString * const kAFGowallaClientID;
|
extern NSString * const kAFGowallaClientID;
|
||||||
extern NSString * const kAFGowallaBaseURLString;
|
extern NSString * const kAFGowallaBaseURLString;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue