Model framework for Cocoa and Cocoa Touch

Overview

Mantle

Carthage compatible CocoaPods Compatible SPM compatible Platform

Mantle makes it easy to write a simple model layer for your Cocoa or Cocoa Touch application.

The Typical Model Object

What's wrong with the way model objects are usually written in Objective-C?

Let's use the GitHub API for demonstration. How would one typically represent a GitHub issue in Objective-C?

typedef enum : NSUInteger {
    GHIssueStateOpen,
    GHIssueStateClosed
} GHIssueState;

@interface GHIssue : NSObject <NSCoding, NSCopying>

@property (nonatomic, copy, readonly) NSURL *URL;
@property (nonatomic, copy, readonly) NSURL *HTMLURL;
@property (nonatomic, copy, readonly) NSNumber *number;
@property (nonatomic, assign, readonly) GHIssueState state;
@property (nonatomic, copy, readonly) NSString *reporterLogin;
@property (nonatomic, copy, readonly) NSDate *updatedAt;
@property (nonatomic, strong, readonly) GHUser *assignee;
@property (nonatomic, copy, readonly) NSDate *retrievedAt;

@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *body;

- (id)initWithDictionary:(NSDictionary *)dictionary;

@end
@implementation GHIssue

+ (NSDateFormatter *)dateFormatter {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'";
    return dateFormatter;
}

- (id)initWithDictionary:(NSDictionary *)dictionary {
    self = [self init];
    if (self == nil) return nil;

    _URL = [NSURL URLWithString:dictionary[@"url"]];
    _HTMLURL = [NSURL URLWithString:dictionary[@"html_url"]];
    _number = dictionary[@"number"];

    if ([dictionary[@"state"] isEqualToString:@"open"]) {
        _state = GHIssueStateOpen;
    } else if ([dictionary[@"state"] isEqualToString:@"closed"]) {
        _state = GHIssueStateClosed;
    }

    _title = [dictionary[@"title"] copy];
    _retrievedAt = [NSDate date];
    _body = [dictionary[@"body"] copy];
    _reporterLogin = [dictionary[@"user"][@"login"] copy];
    _assignee = [[GHUser alloc] initWithDictionary:dictionary[@"assignee"]];

    _updatedAt = [self.class.dateFormatter dateFromString:dictionary[@"updated_at"]];

    return self;
}

- (id)initWithCoder:(NSCoder *)coder {
    self = [self init];
    if (self == nil) return nil;

    _URL = [coder decodeObjectForKey:@"URL"];
    _HTMLURL = [coder decodeObjectForKey:@"HTMLURL"];
    _number = [coder decodeObjectForKey:@"number"];
    _state = [coder decodeUnsignedIntegerForKey:@"state"];
    _title = [coder decodeObjectForKey:@"title"];
    _retrievedAt = [NSDate date];
    _body = [coder decodeObjectForKey:@"body"];
    _reporterLogin = [coder decodeObjectForKey:@"reporterLogin"];
    _assignee = [coder decodeObjectForKey:@"assignee"];
    _updatedAt = [coder decodeObjectForKey:@"updatedAt"];

    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder {
    if (self.URL != nil) [coder encodeObject:self.URL forKey:@"URL"];
    if (self.HTMLURL != nil) [coder encodeObject:self.HTMLURL forKey:@"HTMLURL"];
    if (self.number != nil) [coder encodeObject:self.number forKey:@"number"];
    if (self.title != nil) [coder encodeObject:self.title forKey:@"title"];
    if (self.body != nil) [coder encodeObject:self.body forKey:@"body"];
    if (self.reporterLogin != nil) [coder encodeObject:self.reporterLogin forKey:@"reporterLogin"];
    if (self.assignee != nil) [coder encodeObject:self.assignee forKey:@"assignee"];
    if (self.updatedAt != nil) [coder encodeObject:self.updatedAt forKey:@"updatedAt"];

    [coder encodeUnsignedInteger:self.state forKey:@"state"];
}

- (id)copyWithZone:(NSZone *)zone {
    GHIssue *issue = [[self.class allocWithZone:zone] init];
    issue->_URL = self.URL;
    issue->_HTMLURL = self.HTMLURL;
    issue->_number = self.number;
    issue->_state = self.state;
    issue->_reporterLogin = self.reporterLogin;
    issue->_assignee = self.assignee;
    issue->_updatedAt = self.updatedAt;

    issue.title = self.title;
    issue->_retrievedAt = [NSDate date];
    issue.body = self.body;

    return issue;
}

- (NSUInteger)hash {
    return self.number.hash;
}

- (BOOL)isEqual:(GHIssue *)issue {
    if (![issue isKindOfClass:GHIssue.class]) return NO;

    return [self.number isEqual:issue.number] && [self.title isEqual:issue.title] && [self.body isEqual:issue.body];
}

@end

Whew, that's a lot of boilerplate for something so simple! And, even then, there are some problems that this example doesn't address:

  • There's no way to update a GHIssue with new data from the server.
  • There's no way to turn a GHIssue back into JSON.
  • GHIssueState shouldn't be encoded as-is. If the enum changes in the future, existing archives might break.
  • If the interface of GHIssue changes down the road, existing archives might break.

Why Not Use Core Data?

Core Data solves certain problems very well. If you need to execute complex queries across your data, handle a huge object graph with lots of relationships, or support undo and redo, Core Data is an excellent fit.

It does, however, come with a couple of pain points:

  • There's still a lot of boilerplate. Managed objects reduce some of the boilerplate seen above, but Core Data has plenty of its own. Correctly setting up a Core Data stack (with a persistent store and persistent store coordinator) and executing fetches can take many lines of code.
  • It's hard to get right. Even experienced developers can make mistakes when using Core Data, and the framework is not forgiving.

If you're just trying to access some JSON objects, Core Data can be a lot of work for little gain.

Nonetheless, if you're using or want to use Core Data in your app already, Mantle can still be a convenient translation layer between the API and your managed model objects.

MTLModel

Enter MTLModel. This is what GHIssue looks like inheriting from MTLModel:

typedef enum : NSUInteger {
    GHIssueStateOpen,
    GHIssueStateClosed
} GHIssueState;

@interface GHIssue : MTLModel <MTLJSONSerializing>

@property (nonatomic, copy, readonly) NSURL *URL;
@property (nonatomic, copy, readonly) NSURL *HTMLURL;
@property (nonatomic, copy, readonly) NSNumber *number;
@property (nonatomic, assign, readonly) GHIssueState state;
@property (nonatomic, copy, readonly) NSString *reporterLogin;
@property (nonatomic, strong, readonly) GHUser *assignee;
@property (nonatomic, copy, readonly) NSDate *updatedAt;

@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *body;

@property (nonatomic, copy, readonly) NSDate *retrievedAt;

@end
@implementation GHIssue

+ (NSDateFormatter *)dateFormatter {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'";
    return dateFormatter;
}

+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{
        @"URL": @"url",
        @"HTMLURL": @"html_url",
        @"number": @"number",
        @"state": @"state",
        @"reporterLogin": @"user.login",
        @"assignee": @"assignee",
        @"updatedAt": @"updated_at"
    };
}

+ (NSValueTransformer *)URLJSONTransformer {
    return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
}

+ (NSValueTransformer *)HTMLURLJSONTransformer {
    return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
}

+ (NSValueTransformer *)stateJSONTransformer {
    return [NSValueTransformer mtl_valueMappingTransformerWithDictionary:@{
        @"open": @(GHIssueStateOpen),
        @"closed": @(GHIssueStateClosed)
    }];
}

+ (NSValueTransformer *)assigneeJSONTransformer {
    return [MTLJSONAdapter dictionaryTransformerWithModelClass:GHUser.class];
}

+ (NSValueTransformer *)updatedAtJSONTransformer {
    return [MTLValueTransformer transformerUsingForwardBlock:^id(NSString *dateString, BOOL *success, NSError *__autoreleasing *error) {
        return [self.dateFormatter dateFromString:dateString];
    } reverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) {
        return [self.dateFormatter stringFromDate:date];
    }];
}

- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error {
    self = [super initWithDictionary:dictionaryValue error:error];
    if (self == nil) return nil;

    // Store a value that needs to be determined locally upon initialization.
    _retrievedAt = [NSDate date];

    return self;
}

@end

Notably absent from this version are implementations of <NSCoding>, <NSCopying>, -isEqual:, and -hash. By inspecting the @property declarations you have in your subclass, MTLModel can provide default implementations for all these methods.

The problems with the original example all happen to be fixed as well:

There's no way to update a GHIssue with new data from the server.

MTLModel has an extensible -mergeValuesForKeysFromModel: method, which makes it easy to specify how new model data should be integrated.

There's no way to turn a GHIssue back into JSON.

This is where reversible transformers really come in handy. +[MTLJSONAdapter JSONDictionaryFromModel:error:] can transform any model object conforming to <MTLJSONSerializing> back into a JSON dictionary. +[MTLJSONAdapter JSONArrayFromModels:error:] is the same but turns an array of model objects into an JSON array of dictionaries.

If the interface of GHIssue changes down the road, existing archives might break.

MTLModel automatically saves the version of the model object that was used for archival. When unarchiving, -decodeValueForKey:withCoder:modelVersion: will be invoked if overridden, giving you a convenient hook to upgrade old data.

MTLJSONSerializing

In order to serialize your model objects from or into JSON, you need to implement <MTLJSONSerializing> in your MTLModel subclass. This allows you to use MTLJSONAdapter to convert your model objects from JSON and back:

NSError *error = nil;
XYUser *user = [MTLJSONAdapter modelOfClass:XYUser.class fromJSONDictionary:JSONDictionary error:&error];
NSError *error = nil;
NSDictionary *JSONDictionary = [MTLJSONAdapter JSONDictionaryFromModel:user error:&error];

+JSONKeyPathsByPropertyKey

The dictionary returned by this method specifies how your model object's properties map to the keys in the JSON representation, for example:

@interface XYUser : MTLModel

@property (readonly, nonatomic, copy) NSString *name;
@property (readonly, nonatomic, strong) NSDate *createdAt;

@property (readonly, nonatomic, assign, getter = isMeUser) BOOL meUser;
@property (readonly, nonatomic, strong) XYHelper *helper;

@end

@implementation XYUser

+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{
        @"name": @"name",
        @"createdAt": @"created_at"
    };
}

- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error {
    self = [super initWithDictionary:dictionaryValue error:error];
    if (self == nil) return nil;

    _helper = [XYHelper helperWithName:self.name createdAt:self.createdAt];

    return self;
}

@end

In this example, the XYUser class declares four properties that Mantle handles in different ways:

  • name is mapped to a key of the same name in the JSON representation.
  • createdAt is converted to its snake case equivalent.
  • meUser is not serialized into JSON.
  • helper is initialized exactly once after JSON deserialization.

Use -[NSDictionary mtl_dictionaryByAddingEntriesFromDictionary:] if your model's superclass also implements MTLJSONSerializing to merge their mappings.

If you'd like to map all properties of a Model class to themselves, you can use the +[NSDictionary mtl_identityPropertyMapWithModel:] helper method.

When deserializing JSON using +[MTLJSONAdapter modelOfClass:fromJSONDictionary:error:], JSON keys that don't correspond to a property name or have an explicit mapping are ignored:

NSDictionary *JSONDictionary = @{
    @"name": @"john",
    @"created_at": @"2013/07/02 16:40:00 +0000",
    @"plan": @"lite"
};

XYUser *user = [MTLJSONAdapter modelOfClass:XYUser.class fromJSONDictionary:JSONDictionary error:&error];

Here, the plan would be ignored since it neither matches a property name of XYUser nor is it otherwise mapped in +JSONKeyPathsByPropertyKey.

+JSONTransformerForKey:

Implement this optional method to convert a property from a different type when deserializing from JSON.

+ (NSValueTransformer *)JSONTransformerForKey:(NSString *)key {
    if ([key isEqualToString:@"createdAt"]) {
        return [NSValueTransformer valueTransformerForName:XYDateValueTransformerName];
    }

    return nil;
}

key is the key that applies to your model object; not the original JSON key. Keep this in mind if you transform the key names using +JSONKeyPathsByPropertyKey.

For added convenience, if you implement +<key>JSONTransformer, MTLJSONAdapter will use the result of that method instead. For example, dates that are commonly represented as strings in JSON can be transformed to NSDates like so:

    return [MTLValueTransformer transformerUsingForwardBlock:^id(NSString *dateString, BOOL *success, NSError *__autoreleasing *error) {
        return [self.dateFormatter dateFromString:dateString];
    } reverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) {
        return [self.dateFormatter stringFromDate:date];
    }];
}

If the transformer is reversible, it will also be used when serializing the object into JSON.

+classForParsingJSONDictionary:

If you are implementing a class cluster, implement this optional method to determine which subclass of your base class should be used when deserializing an object from JSON.

@interface XYMessage : MTLModel

@end

@interface XYTextMessage: XYMessage

@property (readonly, nonatomic, copy) NSString *body;

@end

@interface XYPictureMessage : XYMessage

@property (readonly, nonatomic, strong) NSURL *imageURL;

@end

@implementation XYMessage

+ (Class)classForParsingJSONDictionary:(NSDictionary *)JSONDictionary {
    if (JSONDictionary[@"image_url"] != nil) {
        return XYPictureMessage.class;
    }

    if (JSONDictionary[@"body"] != nil) {
        return XYTextMessage.class;
    }

    NSAssert(NO, @"No matching class for the JSON dictionary '%@'.", JSONDictionary);
    return self;
}

@end

MTLJSONAdapter will then pick the class based on the JSON dictionary you pass in:

NSDictionary *textMessage = @{
    @"id": @1,
    @"body": @"Hello World!"
};

NSDictionary *pictureMessage = @{
    @"id": @2,
    @"image_url": @"http://example.com/lolcat.gif"
};

XYTextMessage *messageA = [MTLJSONAdapter modelOfClass:XYMessage.class fromJSONDictionary:textMessage error:NULL];

XYPictureMessage *messageB = [MTLJSONAdapter modelOfClass:XYMessage.class fromJSONDictionary:pictureMessage error:NULL];

Persistence

Mantle doesn't automatically persist your objects for you. However, MTLModel does conform to <NSCoding>, so model objects can be archived to disk using NSKeyedArchiver.

If you need something more powerful, or want to avoid keeping your whole model in memory at once, Core Data may be a better choice.

System Requirements

Mantle supports the following platform deployment targets:

  • macOS 10.10+
  • iOS 9.0+
  • tvOS 9.0+
  • watchOS 2.0+

Importing Mantle

Manually

To add Mantle to your application:

  1. Add the Mantle repository as a submodule of your application's repository.
  2. Run git submodule update --init --recursive from within the Mantle folder.
  3. Drag and drop Mantle.xcodeproj into your application's Xcode project.
  4. On the "General" tab of your application target, add Mantle.framework to the "Embedded Binaries".

If you’re instead developing Mantle on its own, use the Mantle.xcworkspace file.

Carthage

Simply add Mantle to your Cartfile:

github "Mantle/Mantle"

CocoaPods

Add Mantle to your Podfile under the build target they want it used in:

target 'MyAppOrFramework' do
  pod 'Mantle'
end

Then run a pod install within Terminal or the CocoaPods app.

Swift Package Manager

If you are writing an application, add Mantle to your project dependencies directly within Xcode.

If you are writing a package that requires Mantle as dependency, add it to the dependencies list in its Package.swift manifest, for example:

dependencies: [
    .package(url: "https://github.com/Mantle/Mantle.git", .upToNextMajor(from: "2.0.0"))
]

License

Mantle is released under the MIT license. See LICENSE.md.

More Info

Have a question? Please open an issue!

Comments
  • Added NSValueTranformer and reverse transformer capabilities for relationships. Added method - (NSPredicate)managedObjectUniquingPredicate: to MTLManagedObjectSerialization.

    Added NSValueTranformer and reverse transformer capabilities for relationships. Added method - (NSPredicate)managedObjectUniquingPredicate: to MTLManagedObjectSerialization.

    managedObjectUniquingPredicate is used in managedObjectFromModel:insertingIntoContext:processedObjects to attempt to find a managed object that already exists by executing an NSFetchRequest with the provided NSPredicate. It will attempt to fetch this managed object before converting the MTLModel subclass into an NSManagedObject. If a managed object is found then the method will set the values from MTLModel to this discovered managed object instead of creating a new one, otherwise the method will proceed like before.

    This request also includes relationshipModelTransformerForKey: which acts similarly to entityAttributeTransformerForKey:. If a relationshipModelTransformer is described (whether forward or reverse) it will use this to transform between a model and a managed object.

    Closes #114

    opened by rex-remind101 55
  • Adding MTLTransformerErrorHandling

    Adding MTLTransformerErrorHandling

    This adds -mtl_transformedValue:error: and -mtl_reverseTransformedValue:error:.

    • [x] add MTLTransformerErrorHandling protocol
    • [x] add BOOL *success parameter to MTLTransformerErrorHandling
    • [x] implement MTLTransformerErrorHandling on existing transformers
    • [x] use transformedValue:success:error: when (de)serializing models, bubble up errors

    Fixes #152 #142

    breaking changes 
    opened by robb 33
  • Automatic value transformers

    Automatic value transformers

    As brought up in #145, Mantle's adapters could make use of automatic value transformers for common data types that don't have a JSON equivalent. They could also take care of making sure BOOL properties are mapped to CFBoolean-backed NSNumbers.

    Mapping NSURLs to NSStrings comes to mind. NSDate could be transformed to a string, too, but there are many different date representations to chose from.

    If this made it into Mantle, I think I'd prefer using a value transformer for the mapping of BOOLs to CFBooleans over the alternative proposed in #145 since handling all transformations with the same mechanism feels simpler.

    Other than NSURL and BOOL, I can't think of any strong case for automatic mappings right now, however.

    enhancement 
    opened by robb 32
  • Mantle not compatible with Swift

    Mantle not compatible with Swift

    Trying to compile Mantle with Swift project in XCode 6 fails with this error message:

    <unknown>:0: error: cannot override 'init' which has been marked unavailable
    <unknown>:0: error: cannot override 'init' which has been marked unavailable
    <unknown>:0: error: 'init' is unavailable: Replaced by -initWithDictionary:error:
    <unknown>:0: error: 'init' is unavailable: Replaced by -[MTLJSONAdapter initWithJSONDictionary:modelClass:]
    
    bug 
    opened by justMaku 28
  • Core Data adapter

    Core Data adapter

    A MTLManagedObjectAdapter, for transforming MTLModel objects to and from NSManagedObjects.

    To do:

    • [x] Serialize collections to NSManagedObject relationships
    • [x] Deserialize relationships to MTLModel collections
    • [x] Unit tests for serialization
    • [x] Unit tests for deserialization
    • [x] Check +classForDeserializingManagedObject: before deserialization
    • [x] Track objects serialized/deserialized so far to avoid cycles
    • [x] Document private MTLManagedObjectAdapter methods
    opened by jspahrsummers 26
  • Number in JSON does NOT get Converted to NSString Property

    Number in JSON does NOT get Converted to NSString Property

    I have a model with an NSString property. The JSON I receive has a number in place instead. When I convert the JSON to a Mantle model, I do not get an error, but the property is filled with an NSNumber.

    This is VERY dangerous a runtime. Until now I expected Mantle doing the conversion from NSNumber to NSString and the other way around out of the box - which would make sense for robustness.

    Problematic example:

    @interface MantleTestModel : MTLModel <MTLJSONSerializing>
    @property (nonatomic, strong) NSString *stringProperty;
    @end
    
    @implementation MantleTestModel
    + (NSDictionary *)JSONKeyPathsByPropertyKey {
        return @{@"stringProperty": @"stringProperty"};
    }
    @end
    
    
    @implementation MantleTest
    
    - (void)doTest {
        NSDictionary *json = @{@"stringProperty":@666};
        NSError *error = nil;
        MantleTestModel *mantleTestModel = [MTLJSONAdapter modelOfClass:MantleTestModel.class fromJSONDictionary:json error:&error];
        NSParameterAssert(error == nil);
    
        // this raises
        NSParameterAssert([mantleTestModel.stringProperty isKindOfClass:[NSString class]]);
    }
    
    @end
    
    question JSON 
    opened by fabb 25
  • Removing Core Data support from Mantle in 2.0

    Removing Core Data support from Mantle in 2.0

    The main contributors to Mantle right now (@robb and I, basically) are not really Core Data experts, and have been struggling to keep up with the support load regarding MTLManagedObjectAdapter—and our responses probably aren't helpful even when we do get time to reply.

    Since there are a lot of Big Problems™ to solve in that domain, and we're not really the best people to do it, I propose we remove Mantle's Core Data functionality from the main framework in 2.0.

    Of course, Mantle is still designed to be very modular and extensible, and changes like #219 should still help with Core Data integration, so I'd love for others to extract Mantle's current support into a separate project and maintain that separately.

    Thoughts?

    /cc @Mantle/mantle

    breaking changes Core Data 
    opened by jspahrsummers 24
  • Add implicit transformers

    Add implicit transformers

    Here's a shot at #147 that adds hooks to Mantle adapters for automatic transformation. It also automatically transforms NSURLs to NSStrings and also does the CFBoolean thing to BOOLs for JSON serialization.

    Fixes #147 Closes #112

    opened by robb 24
  • Value collection to relationship

    Value collection to relationship

    Hey guys, got a new one for you!

    This pull request allows for MTLManagedObjectAdaptor to perform a fetch request when serializing a to-many relationship from a collection of values.

    Previously, if JSON came over the wire in the following form when retrieving an object:

    {
      "id": 3,
      "children": [4, 7, 8, 29, 100]
    }
    

    I couldn't figure out a way to fetch children by their identifiers when serializing the object via MTLManagedObjectAdaptor.

    So I built in a new method + (NSDictionary *)managedObjectCollectionDescriptionForKey:(NSString *)key; which can also be used by the MTLModel property key pointing to the relationship + (NSDictionary *)childrenManagedObjectCollectionDescription to define an instance where a collection of values should be used to fetch existing objects for a relationship.

    I'm excited to hear what you guys think!

    P.S. Will add tests as soon as I get a confirmation that this is a solid approach :)

    opened by rex-remind101 24
  • Make +JSONKeyPathsByPropertyKey optional

    Make +JSONKeyPathsByPropertyKey optional

    I recently used Mantle on a project when converting JSON into model classes, and it was great! I removed a lot of boilerplate code and my 90% of my models had empty implementations.

    However,

    I had to conform to the MTLJSONSerializing protocol, which requires that + (NSDictionary *)JSONKeyPathsByPropertyKey; be implemented. This seemed rather ridiculous, as the naming conventions of the JSON objects matched the classes, so I just ended up having to implement this method across all the models and return an empty dictionary.

    This patch follows the philosophy of Mantle and removes unnecessary boilerplate.

    opened by ryanmaxwell 24
  • The File

    The File "*.xccconfig" couldn't be opened because it's path couldn't be resolved. It may be missing.

    Steps to reproduce:

    1. git clone git://github.com/github/Mantle.git
    2. run script/bootstrap
    3. Open up the Xcode project
    4. Lots of project integrity warnings, missing Release/Profile/Debug.xcconfig in the Mantle project, iOS-Application/Profile.xcconfig in the Mantle iOS tests, iOS-StaticLibrary/Profile.xcconfig in the Mantle iOS Lib

    I can see the files are in /Mantle/libextobjc/Configuration/, and Xcode will let me view them from within the project, but for whatever reason I have to remove/re-add them to the project for Xcode to recognize them.

    bug 
    opened by sneakyness 24
Releases(2.2.0)
  • 2.2.0(Jun 18, 2021)

    • Raised the minimum deployment version to iOS 9 and above, courtesy of @mathaeus in #886.
      • While this is technically a breaking change per the rules of semver, we believe that the number of apps still shipping to iOS 8 to be minimal. If this affects you, there is no reason to update yet as there have been no new features. Please do get in touch however.
    Source code(tar.gz)
    Source code(zip)
  • 2.1.7(May 8, 2021)

  • 2.1.6(Oct 17, 2020)

  • 2.1.5(Oct 14, 2020)

  • 2.1.4(Sep 26, 2020)

  • 2.1.3(Sep 22, 2020)

  • 2.1.2(Sep 18, 2020)

  • 2.1.1(Jan 27, 2020)

    • Block definition fix for mtl_cleanupBlock_t (@mogelbuster in #822)
    • Suppress documentation warnings for @encode (@Konshin in #785)
    • Xcode 10.2 compatibility (@yhkaplan in #834)
    • Spring cleaning of libextobjc (@robb in #844)
    • Error added for passing nil JSON dictionary to -[MTLJSONAdapter modelFromJSONDictionary:error:](@hashier in #751)
    • Cocoapods is now supported officially (@abotkin-cpi in #846)
    • GitHub Actions added (@robb in #844 & @dcaunt in #804)
    • Carthage updates (@dcaunt in #804 & @alexpezzi in #809)
    Source code(tar.gz)
    Source code(zip)
  • 2.1.0(Oct 12, 2016)

    • watchOS support (@ikesyo in #730)
    • tvOS support (@ikesyo in #731)
    • Xcode 8 support (@dcaunt in #758)
    • Added implicit NSUUID JSON value transformer (@conraddev in #723)

    Also includes documentation improvements thanks to @getaaron and @bruun. Thanks to @ikesyo for Xcode/Travis maintenance.

    Source code(tar.gz)
    Source code(zip)
    Mantle.framework.zip(3.84 MB)
  • 2.0.7(Apr 15, 2016)

    • MTLJSONAdapter correctly checks for MTLModel protocol conformance rather than MTLModel inheritance @startupthekid in #617, @priteshshah1983 in #631)
    • Improved error descriptions when serializing models from JSON fails (@kypselia in #661)
    • Add predefined NSDate, NSNumber and NSFormatter value transformer factory methods (@conradev in #641)
    • Fix Swift deprecation warnings (@msanders in #680)
    • Apply default MTLJSONAdapter type transformer for a key when using JSONTransformerForKey: if no custom transformer is returned (@k06a in #685)

    Thanks to @robb for reviewing pull requests!

    Source code(tar.gz)
    Source code(zip)
    Mantle.framework.zip(2.01 MB)
  • 1.5.8(Jun 10, 2016)

  • 1.5.7(Feb 24, 2016)

  • 1.5.6(Oct 15, 2015)

  • 2.0.5(Sep 15, 2015)

  • 2.0.4(Aug 13, 2015)

  • 2.0.3(Aug 4, 2015)

    • Unmapped, optional protocol properties are now using MTLStoragePropertyNone (@kevin-traansmission in #523)
    • MTLJSONAdapter subclasses now behave correctly with class clusters (@hengw in #556)
    • Copying a MTLModel skips revalidation for better performance (@zadr in #548)
    • Fewer MTLJSONAdapter allocations in class-based transformers (@jmah in #567)
    • Correctly handle storage behavior for optional properties or those declared in a super class (@jmah in #568)

    Also includes improvements to the README by @danielgalasko @alikaragoz :sparkling_heart:

    Source code(tar.gz)
    Source code(zip)
    Mantle.framework.zip(248.89 KB)
  • 2.0.2(May 23, 2015)

  • 2.0.1(May 22, 2015)

  • 2.0(Apr 1, 2015)

  • 2.0-beta.1(Mar 17, 2015)

  • 1.5.3(Dec 30, 2014)

  • 1.5.2(Nov 21, 2014)

  • 1.5.1(Oct 7, 2014)

    • Ordered Core Data relationships will now be serialized into NSOrderedSet
    • Illegal mappings in +JSONKeyPathsByPropertyKey now throw an exception

    With kind contributions by @5teev, @Ahti, @alanrogers, @joshaber, @jspahrsummers, @kylef, @mdiep, @mickeyreiss, @rawrjustin, @robb and @tomtaylor.

    Source code(tar.gz)
    Source code(zip)
  • 1.5(May 25, 2014)

    • Adds Mantle.xcworkspace for easier development and integration.
    • Adds convenience methods for serializing and deserializing arrays of MTLModels to JSON.
    • Adds default values for value mapping transformers.
    • If +JSONKeyPathByPropertyKey or +managedObjectKeysByPropertyKey map to property keys not part of +[MTLModel propertyKeys], an error is returned.
    • -[MTLModel mergeValuesForKeysFromModel:] now property handles merging between subclasses.
    • Prevents associated managed objects from being updated with incomplete data.

    With kind contributions by @DAloG, @bartvandendriessche, @robrix, @jspahrsummers, @robb, @paulthorsteinson, @paulyoung and @kilink :sparkling_heart:

    Source code(tar.gz)
    Source code(zip)
  • 1.4.1(Mar 11, 2014)

    • Fixes a regression introduced in 1.4. which broke access to JSON key paths containing non-dictionary elements.
    • Adds compatibility with Xcode 5.1
    Source code(tar.gz)
    Source code(zip)
  • 1.4(Mar 1, 2014)

    • Improved error handling
    • Support for arm64
    • Improved bubbling up of Core Data errors
    • Handle model initialization with invalid data-structures
    • Expose -JSONKeyPathForKey:
    • Handle illegal key paths
    • mtl_valueMappingTransformerWithDictionary: uses NSNull as default input value
    • Log class and key when decoding fails

    With kind contributions by @dcordero, @keithduncan, @jspahrsummers, @jilouc, @maxgoedjen, @robb, @dcaunt, @dannygreg, @joshaber, @bdolman, @alanjrogers, @ColinEberhardt, @blueless, @dataxpress, @kylef, @eliperkins, @notjosh and @dblock :sparkling_heart:

    Source code(tar.gz)
    Source code(zip)
Owner
Model framework for Cocoa and Cocoa Touch
null
HandyJSON is a framework written in Swift which to make converting model objects to and from JSON easy on iOS.

HandyJSON To deal with crash on iOS 14 beta4 please try version 5.0.3-beta HandyJSON is a framework written in Swift which to make converting model ob

Alibaba 4.1k Dec 29, 2022
ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects to and from JSON.

ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from J

Tristan Himmelman 9k Jan 2, 2023
Easy JSON to NSObject mapping using Cocoa's key value coding (KVC)

#Motis Object Mapping Easy JSON to NSObject mapping using Cocoa's key value coding (KVC) Motis is a user-friendly interface with Key Value Coding that

Mobile Jazz 249 Jun 29, 2022
JSONExport is a desktop application for Mac OS X which enables you to export JSON objects as model classes with their associated constructors, utility methods, setters and getters in your favorite language.

JSONExport JSONExport is a desktop application for Mac OS X written in Swift. Using JSONExport you will be able to: Convert any valid JSON object to a

Ahmed Ali 4.7k Dec 30, 2022
🌟 Super light and easy automatic JSON to model mapper

magic-mapper-swift ?? Super light and easy automatic JSON to model mapper Finish writing README.md Ability to map NSManagedObject Ability to convert m

Adrian Mateoaea 26 Oct 6, 2019
JSONNeverDie - Auto reflection tool from JSON to Model, user friendly JSON encoder / decoder, aims to never die

JSONNeverDie is an auto reflection tool from JSON to Model, a user friendly JSON encoder / decoder, aims to never die. Also JSONNeverDie is a very important part of Pitaya.

John Lui 454 Oct 30, 2022
Mappable - Flexible JSON to Model converter, specially optimized for immutable properties

Mappable is a lightweight, flexible, easy-to-use framework to convert JSON to model, specially optimized for immutable property initializatio

Leave 27 Aug 26, 2022
Dogtector: dog breed detection app for iOS using YOLOv5 model combined with Metal based object decoder optimized

Dogtector Project description Dogtector is dog breed detection app for iOS using YOLOv5 model combined with Metal based object decoder optimized for u

Bartłomiej Pluta 21 Aug 1, 2022
Elevate is a JSON parsing framework that leverages Swift to make parsing simple, reliable and composable

Elevate is a JSON parsing framework that leverages Swift to make parsing simple, reliable and composable. Elevate should no longer be used for

Nike Inc. 611 Oct 23, 2022
This framework implements a strict JSON parser and generator in Objective-C.

SBJson 5 Chunk-based JSON parsing and generation in Objective-C. Overview SBJson's number one feature is stream/chunk-based operation. Feed the parser

null 3.8k Jan 5, 2023
Magical Data Modeling Framework for JSON - allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS and tvOS apps.

JSONModel - Magical Data Modeling Framework for JSON JSONModel allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS

JSONModel 6.9k Dec 8, 2022
Magical Data Modeling Framework for JSON - allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS and tvOS apps.

JSONModel - Magical Data Modeling Framework for JSON JSONModel allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS

JSONModel 6.8k Nov 19, 2021
Swift/Obj-C HTTP framework with a focus on REST and JSON

Now Archived and Forked PMHTTP will not be maintained in this repository going forward. Please use, create issues on, and make PRs to the fork of PHMT

Postmates Inc. 509 Sep 4, 2022
Freddy - A reusable framework for parsing JSON in Swift.

Why Freddy? Parsing JSON elegantly and safely can be hard, but Freddy is here to help. Freddy is a reusable framework for parsing JSON in Swift. It ha

Big Nerd Ranch 1.1k Jan 1, 2023
An iOS framework for creating JSON-based models. Written in Swift.

An iOS framework for creating JSON-based models. Written in Swift (because it totally rules!) Requirements iOS 8.0+ Xcode 7.3 Swift 2.2 Installation E

Oven Bits 448 Nov 8, 2022
Reflection based (Dictionary, CKRecord, NSManagedObject, Realm, JSON and XML) object mapping with extensions for Alamofire and Moya with RxSwift or ReactiveSwift

EVReflection General information At this moment the master branch is tested with Swift 4.2 and 5.0 beta If you want to continue using EVReflection in

Edwin Vermeer 964 Dec 14, 2022
A protocol to serialize Swift structs and classes for encoding and decoding.

Serpent (previously known as Serializable) is a framework made for creating model objects or structs that can be easily serialized and deserialized fr

Nodes - iOS 287 Nov 11, 2022
Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend

Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend. Using Argo

thoughtbot, inc. 3.5k Dec 20, 2022
Decodable Simple and strict, yet powerful object mapping made possible by Swift 2's error handling.

Decodable Simple and strict, yet powerful object mapping made possible by Swift 2's error handling. Greatly inspired by Argo, but without a bizillion

Johannes Lund 1k Jul 15, 2022