CocoaPods trunk is moving to be read-only. Read more on the blog, there are 18 months to go.
TestsTested | ✓ |
LangLanguage | Obj-CObjective C |
License | BSD |
ReleasedLast Release | Sep 2016 |
SPMSupports SPM | ✓ |
Maintained by Ryan Dignard.
RestGoatee-Core is a framework which takes raw NSDictionary
and NSXMLParser
objects and convienently converts them to your own domain models.
Supports: iOS 5.0, OS X 10.7, watchOS 1.0, tvOS 9.0; requires ARC
This library's aim is one of simplicity in the common case and extensibility in the general case:
1) The act of translating a data source to a domain model is not the place for business logic or key translation.
2) The API layer should be able to handle new objects and object properties seemlessly without requiring new deserialization logic. This commit in the example project added an entirely new response object without fanfare.
3) Due to JSON and XML having limited types, the deserializer needs to be able to intelligently map to a larger standard family of types.
4) CoreData support is usually not done at the outset of a project; this library makes it easier to turn it on with minimal refactoring. CoreData support is implicit, but inactive in projects without it.
5) The default mapping behavior should be both generally intuitive (correct 99% of the time) and extensible.
6) The default should be the least verbose in terms of complexity and lines of code. You don't specify mappings for objects or properties that are one-to-one, well named, and explicitly typed.
Consider your favorite or most popular model framework:
NSManagedObject
subclasses? foo-bar
foo_bar
and fooBar
are likely the same key? pod 'RestGoatee-Core'
to your Podfile and run pod install
.github "rdignard08/RestGoatee-Core" "master"
(you may also specify a release tag instead of master).#import "RestGoatee-Core.h"
to include all public headers and start using the library. @interface BaseObject : NSObject
@property (nonatomic, strong) NSString* stringValue;
@property (nonatomic, strong) NSNumber* numberValue;
@property (nonatomic, assign) double doubleValue;
@end
@interface DerivedObject : BaseObject
@property (nonatomic, strong) NSDate* dateValue;
@property (nonatomic, strong) id rawValue;
@end
DerivedObject
with an NSDictionary
:DerivedObject* derived = [DerivedObject objectFromDataSource:@{
@"stringValue" : @"aString",
@"numberValue" : @3,
@"doubleValue" : @3.14,
@"dateValue" : @"2016-01-17T16:13:00-0800",
@"rawValue" : [NSNull null]
} inContext:nil];
assert([derived.stringValue isEqual:@"aString"]);
assert([derived.numberValue isEqual:@3]);
assert(derived.doubleValue == 3.14);
assert([derived.dateValue timeIntervalSince1970] == 1453075980.0);
assert(derived.rawValue == [NSNull null]);
Making an object is as simple as that. Supported data sources out of the box are NSDictionary
(for JSON) and RGXMLNode
(for XML), but the protocol is public and you can freely make your own data source.
DerivedObject* derived = [DerivedObject objectFromDataSource:@{ @"stringValue" : @"aString" } inContext:nil];
assert([derived.stringValue isEqual:@"aString"]);
assert(derived.numberValue == nil);
assert(derived.doubleValue == 0.0);
If a value isn't provided it remains the default value. Likewise, if there are keys which aren't used they'll be ignored.
NSNull
or the value?DerivedObject* derived = [DerivedObject objectFromDataSource:@{ @"stringValue" : [NSNull null] } inContext:nil];
assert(derived.stringValue == nil);
The rules are pretty simple, and guarantee you will never break the type system (an NSURL*
property will always have an NSURL
or nil
).
id
or NSObject*
will receive any value.NSNumber
=> NSString
through .stringValue
for example) it gets set to the converted value.
NSString
/ NSNumber
maps to id
, NSObject
, NSNumber
, NSURL
, NSDate
, Class
, and primitives (int
, double
, char
, etc.)RGXMLNode
maps to NSDictionary
then NSDictionary
maps to NSDictionary
or an NSObject
subclass etc.NSObject+RGDeserializationSpec.m
DerivedObject* derived = [DerivedObject objectFromDataSource:@{ @"string_value" : @"aString" } inContext:nil];
assert([derived.stringValue isEqual:@"aString"]);
Not CamelCase? No problem. The implicit mapping will handle all cases where the case insensitive ASCII alphabet and numbers of the keys match.
@implementation DerivedObject
+ (NSDictionary*) overrideKeysForMapping {
return @{ @"super_secret_str" : @"stringValue" };
}
@end
DerivedObject* derived = [DerivedObject objectFromDataSource:@{ @"super_secret_str" : @"aString" } inContext:nil];
assert([derived.stringValue isEqual:@"aString"]);
Providing +overrideKeysForMapping
gives you the flexibility to map a key to the name of the property. Any key not specified goes through the default process so you only need to specify the exceptions.
@implementation DerivedObject
- (BOOL) shouldTransformValue:(id)value forProperty:(NSString*)propertyName {
if ([propertyName isEqual:@"stringValue"]) {
self.stringValue = [value description].uppercaseString;
return NO;
}
return YES;
}
@end
DerivedObject* derived = [DerivedObject objectFromDataSource:@{ @"stringValue" : @"abcd" } inContext:nil];
assert([derived.stringValue isEqual:@"ABCD"]);
You can override -shouldTransformValue:forProperty:
and return NO
whenever you want to take control directly.
DerivedObject* derived = [DerviedObject new];
derived.stringValue = @"aString";
derived.numberValue = @3;
derived.doubleValue = 3.0;
NSDictionary* dictionaryRepresentation = [derived dictionaryRepresentation];
assert([dictionaryRepresentation[@"stringValue"] isEqual:@"aString"]);
assert([dictionaryRepresentation[@"numberValue"] isEqual:@"3"]);
assert([dictionaryRepresentation[@"doubleValue"] isEqual:@"3"]);
-dictionaryRepresentation
returns a dictionary where the keys are the names of the properties and the values are the result of serializing that value. A property of type NSString*
, NSURL*
, NSNumber*
, or a primitive will be a value of NSString*
. NSNull*
values stay the same. NSArray*
, NSDictionary*
, and all other NSObject*
subclasses are output by applying the same rules to their sub objects.
For a working example see https://github.com/rdignard08/RestGoatee
BSD Simplified (2-clause)