{"id":1712,"url":"https://github.com/Yalantis/FastEasyMapping","last_synced_at":"2025-08-02T04:32:21.156Z","repository":{"id":14938641,"uuid":"17663173","full_name":"Yalantis/FastEasyMapping","owner":"Yalantis","description":"A tool for fast serializing \u0026 deserializing of JSON","archived":false,"fork":false,"pushed_at":"2019-12-07T16:20:56.000Z","size":1573,"stargazers_count":548,"open_issues_count":18,"forks_count":77,"subscribers_count":42,"default_branch":"master","last_synced_at":"2025-07-26T07:50:27.651Z","etag":null,"topics":["coredata","deserialization","json-map","json-serialization","mapping","objective-c","serialization","xcode","yalantis"],"latest_commit_sha":null,"homepage":"https://yalantis.com/","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Yalantis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-12T10:28:07.000Z","updated_at":"2025-04-21T18:14:15.000Z","dependencies_parsed_at":"2022-07-22T09:52:49.067Z","dependency_job_id":null,"html_url":"https://github.com/Yalantis/FastEasyMapping","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"purl":"pkg:github/Yalantis/FastEasyMapping","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yalantis%2FFastEasyMapping","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yalantis%2FFastEasyMapping/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yalantis%2FFastEasyMapping/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yalantis%2FFastEasyMapping/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Yalantis","download_url":"https://codeload.github.com/Yalantis/FastEasyMapping/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yalantis%2FFastEasyMapping/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268334615,"owners_count":24233793,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coredata","deserialization","json-map","json-serialization","mapping","objective-c","serialization","xcode","yalantis"],"created_at":"2024-01-05T20:15:54.017Z","updated_at":"2025-08-02T04:32:20.737Z","avatar_url":"https://github.com/Yalantis.png","language":"Objective-C","funding_links":[],"categories":["Parsing","Objective-C"],"sub_categories":["JSON","Other free courses"],"readme":"[![GitHub release](https://img.shields.io/github/release/Yalantis/FastEasyMapping.svg)](https://github.com/Yalantis/FastEasyMapping/releases)\n[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/FastEasyMapping.svg)](https://img.shields.io/cocoapods/v/FastEasyMapping.svg)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![Build Status](https://travis-ci.org/Yalantis/FastEasyMapping.svg?branch=master)](https://travis-ci.org/Yalantis/FastEasyMapping)\n[![codecov.io](https://codecov.io/github/Yalantis/FastEasyMapping/coverage.svg?branch=master)](https://codecov.io/github/Yalantis/FastEasyMapping?branch=master)\n\n# FastEasyMapping\n- [Overview](#overview)\n- [Requirements](#requirements)\n- [Installation](#installation)\n\t- [CocoaPods](#cocoapods)\n\t- [Carthage](#carthage)\n- [Usage](#usage)\n\t- [Deserialization](#deserialization)\n\t- [Serialization](#serialization)\n- [Mapping](#mapping)\n\t- [Attributes](#femattribute)\n\t- [Relationships](#femrelationship)\n\t- [Assignment policy](#assignment-policy)\n- [Uniquing](#uniquing)\n\t- [Relationship bindings](#relationship-bindings-by-pk)\n\t- [Weak relationship](#weak-relationship)\n- [Delegation](#delegation)\n- [Releases/Changelog](https://github.com/Yalantis/FastEasyMapping/releases)\n- [Thanks](#thanks)\n\n### Note\nThis is a fork of [EasyMapping](https://github.com/EasyMapping/EasyMapping), a flexible and easy framework for JSON mapping.\n\n## Overview\nIt turns out, that almost all popular libraries for JSON mapping are SLOW. The main reason for that is multiple trips to database during the lookup of existing objects. We [decided](https://yalantis.com/blog/from-json-to-core-data-fast-and-effectively/) to take an already existing [flexible solution](https://github.com/EasyMapping/EasyMapping) (i.e. EasyMapping) and improve its overall performance.\n\n\u003e Benchmark done on June/2014. Results may be outdated (EasyMapping performs nearly identical nowadays).\n\n\u003cp align=\"center\" \u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/Yalantis/FastEasyMapping/efabb88b0831c7ece88e728b9665edc4d3af5b1f/Assets/performance.png\" alt=\"FastEasyMapping\" title=\"FastEasyMapping\"\u003e\n\u003c/p\u003e\n\n\n## Requirements\nPlatform | Min Deployment Target\n:---: | :---:\niOS | 8.0\nmacOS | 10.10\ntvOS | 9.0\nwatchOS | 2.0\n\nBuild using Xcode 8.3.2+\n\n## Installation\n### CocoaPods\n[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:\n\n```bash\n$ gem install cocoapods\n```\nTo integrate FastEasyMapping into your Xcode project using CocoaPods, specify it in your `Podfile`:\n\n```ruby\nsource 'https://github.com/CocoaPods/Specs.git'\nplatform :ios, '10.0'\nuse_frameworks!\n\ntarget '\u003cYour Target Name\u003e' do\n    pod 'FastEasyMapping', '~\u003e 1.2'\nend\n```\n\nThen, run the following command:\n\n```bash\n$ pod install\n```\n\n### Carthage\n[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.\n\nYou can install Carthage with [Homebrew](http://brew.sh/) using the following command:\n\n```bash\n$ brew update\n$ brew install carthage\n```\n\nTo integrate FastEasyMappingRealm into your Xcode project using Carthage, specify it in your `Cartfile`:\n\n```ogdl\ngithub \"Yalantis/FastEasyMapping\" ~\u003e 1.2\n```\n\nRun `carthage update` to build the framework and drag the built `FastEasyMapping.framework` into your Xcode project. \n\n## Usage\n### Deserialization\n\nToday NSObject and NSManagedObject mapping are supported out of the box. Lets take a look at how a basic mapping looks like: For example, we have JSON:\n\n```json\n{\n    \"name\": \"Lucas\",\n    \"user_email\": \"lucastoc@gmail.com\",\n    \"car\": {\n        \"model\": \"i30\",\n        \"year\": \"2013\"\n    },\n    \"phones\": [\n        {\n            \"ddi\": \"55\",\n            \"ddd\": \"85\",\n            \"number\": \"1111-1111\"\n        },\n        {\n            \"ddi\": \"55\",\n            \"ddd\": \"11\",\n            \"number\": \"2222-222\"\n        }\n    ]\n}\n```\n\nand corresponding [CoreData](https://www.objc.io/issues/4-core-data/core-data-overview/)-generated classes: \n\n```objective-c\n@interface Person : NSManagedObject\n\n@property (nonatomic, retain) NSString *name;\n@property (nonatomic, retain) NSString *email;\n@property (nonatomic, retain) Car *car;\n@property (nonatomic, retain) NSSet *phones;\n\n@end\n\n@interface Car : NSManagedObject\n\n@property (nonatomic, retain) NSString *model;\n@property (nonatomic, retain) NSString *year;\n@property (nonatomic, retain) Person *person;\n\n@end\n\n@interface Phone : NSManagedObject\n\n@property (nonatomic, retain) NSString *ddi;\n@property (nonatomic, retain) NSString *ddd;\n@property (nonatomic, retain) NSString *number;\n@property (nonatomic, retain) Person *person;\n\n@end\n```\n\nIn order to map _JSON to Object_ and vice versa we have to describe the mapping rules:\n\n```objective-c\n@implementation Person (Mapping)\n\n+ (FEMMapping *)defaultMapping {\n    FEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@\"Person\"];\n    [mapping addAttributesFromArray:@[@\"name\"]];\n    [mapping addAttributesFromDictionary:@{@\"email\": @\"user_email\"}];\n\n    [mapping addRelationshipMapping:[Car defaultMapping] forProperty:@\"car\" keyPath:@\"car\"];\n    [mapping addToManyRelationshipMapping:[Phone defaultMapping] forProperty:@\"phones\" keyPath:@\"phones\"];\n\n    return mapping;\n}\n\n@end\n\n@implementation Car (Mapping)\n\n+ (FEMMapping *)defaultMapping {\n    FEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@\"Car\"];\n    [mapping addAttributesFromArray:@[@\"model\", @\"year\"]];\n\n    return mapping;\n}\n\n@end\n\n\n@implementation Phone (Mapping)\n\n+ (FEMMapping *)defaultMapping {\n    FEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@\"Phone\"];\n    [mapping addAttributesFromArray:@[@\"number\", @\"ddd\", @\"ddi\"]];\n\n    return mapping;\n}\n\n@end\n```\n\nNow we can deserialize _JSON to Object_ easily:\n\n```objective-c\nFEMMapping *mapping = [Person defaultMapping];\nPerson *person = [FEMDeserializer objectFromRepresentation:json mapping:mapping context:managedObjectContext];\n```\n\nOr collection of Objects:\n\n```objective-c\nNSArray *persons = [FEMDeserializer collectionFromRepresentation:json mapping:mapping context:managedObjectContext];\n```\n\nOr even update an Object:\n```objective-c\n[FEMDeserializer fillObject:person fromRepresentation:json mapping:mapping];\n\n```\n\n### Serialization\n\nAlso we can serialize an _Object to JSON_ using the mapping defined above:\n```objective-c\nFEMMapping *mapping = [Person defaultMapping];\nPerson *person = ...;\nNSDictionary *json = [FEMSerializer serializeObject:person usingMapping:mapping];\n```\n\nOr collection to JSON: \n```objective-c\nFEMMapping *mapping = [Person defaultMapping];\nNSArray *persons = ...;\nNSArray *json = [FEMSerializer serializeCollection:persons usingMapping:mapping];\n```\n\n## Mapping\n### FEMAttribute\n`FEMAttribute` is a core class of FEM. Briefly it is a description of relationship between the Object's `property` and the JSON's `keyPath`. Also it encapsulates knowledge of how the value needs to be mapped from _Object to JSON_ and back via blocks. \n\n```objective-c\ntypedef __nullable id (^FEMMapBlock)(id value __nonnull);\n\n@interface FEMAttribute : NSObject \u003cFEMProperty\u003e\n\n@property (nonatomic, copy, nonnull) NSString *property;\n@property (nonatomic, copy, nullable) NSString *keyPath;\n\n- (nonnull instancetype)initWithProperty:(nonnull NSString *)property keyPath:(nullable NSString *)keyPath map:(nullable FEMMapBlock)map reverseMap:(nullable FEMMapBlock)reverseMap;\n\n- (nullable id)mapValue:(nullable id)value;\n- (nullable id)reverseMapValue:(nullable id)value;\n\n@end\n```\n\nAlongside with `property` and `keyPath` value you can pass mapping blocks that allow to describe completely custom mappings.\n\nExamples:\n\n#### Mapping of value with the same keys and type:\n```objective-c\nFEMAttribute *attribute = [FEMAttribute mappingOfProperty:@\"url\"];\n// or \nFEMAttribute *attribute = [[FEMAttribute alloc] initWithProperty:@\"url\" keyPath:@\"url\" map:NULL reverseMap:NULL];\n``` \n\n#### Mapping of value with different keys and the same type:\n```objective-c\nFEMAttribute *attribute = [FEMAttribute mappingOfProperty:@\"urlString\" toKeyPath:@\"URL\"];\n// or \nFEMAttribute *attribute = [[FEMAttribute alloc] initWithProperty:@\"urlString\" keyPath:@\"URL\" map:NULL reverseMap:NULL];\n``` \n\n#### Mapping of different types:\nQuite often value type in JSON needs to be converted to more useful internal representation. For example HEX to `UIColor`, `String` to `NSURL`, `Integer` to `enum` and so on. For this purpose you can use `map` and `reverseMap` properties. For example lets describe attribute that maps `String` to [NSDate](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/) using [NSDateFormatter](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/):\n```objective-c\nNSDateFormatter *formatter = [[NSDateFormatter alloc] init];\n[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@\"en_US_POSIX\"]];\n[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@\"UTC\"]];\n[formatter setDateFormat:@\"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\"];\n\nFEMAttribute *attribute = [[FEMAttribute alloc] initWithProperty:@\"updateDate\" keyPath:@\"timestamp\" map:^id(id value) {\n\tif ([value isKindOfClass:[NSString class]]) {\n\t\treturn [formatter dateFromString:value];\n\t} \n\treturn nil;\n} reverseMap:^id(id value) {\n\treturn [formatter stringFromDate:value];\n}];\n```\nFirst of all we've defined [NSDateFormatter](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/) that fits our requirements. Next step is to define Attribute instance with correct mapping. Briefly `map` block is invoked during deserialization (_JSON to Object_) while `reverseMap` is used for serialization process. Both are quite stratforward with but with few gotchas: \n\n- `map` can receive `NSNull` instance. This is a valid case for `null` value in JSON.\n- map won't be invoked for missing keys. Therefore, if JSON doesn't contain keyPath specified by your attribute, reverse mapping not called.\n- from map you can return either `nil` or `NSNull` for empty values\n- `reverseMap` invoked only when `property` contains a non-nil value.\t\n- from `reverseMap` you can return either `nil` or `NSNull`. Both will produce `{\"keyPath\": null}`\n\n#### Adding attribute to FEMMapping\nThere are several shortcuts that allow you to add attributes easier to the mapping itself:\n##### Explicitly\n```objective-c\nFEMMapping *mapping = [[FEMMapping alloc] initWithObjectClass:[Person class]];\nFEMAttribute *attribute = [FEMAttribute mappingOfProperty:@\"url\"];\n[mapping addAttribute:attribute];\n```\n\n##### Implicitly\n```objective-c\nFEMMapping *mapping = [[FEMMapping alloc] initWithObjectClass:[Person class]];\n[mapping addAttributeWithProperty:@\"property\" keyPath:@\"keyPath\"];\n```\n\n##### As a Dictionary\n```objective-c\nFEMMapping *mapping = [[FEMMapping alloc] initWithObjectClass:[Person class]];\n[mapping addAttributesFromDictionary:@{@\"property\": @\"keyPath\"}];\n```\n\n##### As an Array\nUseful when the `property` is equal to the `keyPath`:\n```objective-c\nFEMMapping *mapping = [[FEMMapping alloc] initWithObjectClass:[Person class]];\n[mapping addAttributesFromArray:@[@\"propertyAndKeyPathAreTheSame\"]];\n```\n\n### FEMRelationship\n`FEMRelationship` is a class that describes relationship between two `FEMMapping` instances. \n```objective-c\n@interface FEMRelationship\n\n@property (nonatomic, copy, nonnull) NSString *property;\n@property (nonatomic, copy, nullable) NSString *keyPath;\n\n@property (nonatomic, strong, nonnull) FEMMapping *mapping;\n@property (nonatomic, getter=isToMany) BOOL toMany;\n\n@property (nonatomic) BOOL weak;\n@property (nonatomic, copy, nonnull) FEMAssignmentPolicy assignmentPolicy;\n\n@end\n```\n\nRelationship is also bound to a `property` and `keyPath`. Obviously, it has a reference to Object's `FEMMapping` and a flag that indicates whether it’s a to-many relationship. Moreover, it allows you to specify assignment policy and \"weakifying\" behaviour of the relationship.\n\nExample: \n\n```objective-c\nFEMMapping *childMapping = ...;\n\nFEMRelationship *childRelationship = [[FEMRelationship alloc] initWithProperty:@\"parentProperty\" keyPath:@\"jsonKeyPath\" mapping:childMapping];\nchildRelationship.toMany = YES;\n```\n\n#### Assignment policy\nAssignment policy describes how deserialized relationship value should be assigned to a property. FEM supports 5 policies out of the box:\n\n- `FEMAssignmentPolicyAssign` - replace Old property's value by New. Designed for to-one and to-many relationship. Default policy.\n- `FEMAssignmentPolicyObjectMerge` - assigns New relationship value unless it is `nil`. Designed for to-one relationship.\n- `FEMAssignmentPolicyCollectionMerge` - merges a New and Old values of relationship. Supported collections are: [NSSet](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSSet_Class/), [NSArray](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/), [NSOrderedSet](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSOrderedSet_Class/) and their successors. Designed for to-many relationship.\n- `FEMAssignmentPolicyObjectReplace` - replaces Old value with New by deleting Old. Designed for to-one relationship.\n- `FEMAssignmentPolicyCollectionReplace` - deletes objects not presented in [union](https://en.wikipedia.org/wiki/Union_(set_theory)) of New and Old values sets. Union set is used as a New value. Supported collections are: [NSSet](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSSet_Class/), [NSArray](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/), [NSOrderedSet](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSOrderedSet_Class/) and their successors. Designed for to-many relationship.\n\n#### Adding relationship to FEMMapping\n\n##### Explicitly\n```objective-c\nFEMMapping *mapping = [[FEMMapping alloc] initWithObjectClass:[Person class]];\nFEMMapping *carMapping = [[FEMMapping alloc] initWithObjectClass:[Car class]];\n\nFEMRelationship *carRelationship = [[FEMRelationship alloc] initWithProperty:@\"car\" keyPath:@\"car\" mapping:carMapping];\n[mapping addRelationship:carRelationship];\n```\n\n##### Implicitly\n```objective-c\nFEMMapping *mapping = [[FEMMapping alloc] initWithObjectClass:[Person class]];\nFEMMapping *phoneMapping = [[FEMMapping alloc] initWithObjectClass:[Phone class]];\n\n[mapping addToManyRelationshipMapping:phoneMapping property:@\"phones\" keyPath:@\"phones\"];\n```\n\n### FEMMapping\nGenerally `FEMMapping` is a class that describes mapping for `NSObject` or `NSManagedObject` by encapsulating a set of attributes and relationships. In addition, it defines the possibilities for objects uniquing (supported by CoreData only).\n\nThe only difference between `NSObject` and `NSManagedObject` is in `init` methods:\n\n##### NSObject\n```objective-c\nFEMMapping *objectMapping = [[FEMMapping alloc] initWithObjectClass:[CustomNSObjectSuccessor class]];\n```\n\n##### NSManagedObject\n```objective-c\nFEMMapping *managedObjectMapping = [[FEMMapping alloc] initWithEntityName:@\"EntityName\"];\n```\n\n#### Root Path\nSometimes a desired JSON is nested by a keyPath. In this case you can use `rootPath` property. Let’s modify Person JSON by nesting Person representation:\n```\n{\n\tresult: {\n\t\t\"name\": \"Lucas\",\n    \t\"user_email\": \"lucastoc@gmail.com\",\n    \t\"car\": {\n        \t\"model\": \"i30\",\n        \t\"year\": \"2013\"\n    \t}\n\t}\n}\n```\n\nMapping will look like this:\n```objective-c\n@implementation Person (Mapping)\n\n+ (FEMMapping *)defaultMapping {\n    FEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@\"Person\"];\n    mapping.rootPath = @\"result\";\n\n    [mapping addAttributesFromArray:@[@\"name\"]];\n    [mapping addAttributesFromDictionary:@{@\"email\": @\"user_email\"}];\n    [mapping addRelationshipMapping:[Car defaultMapping] forProperty:@\"car\" keyPath:@\"car\"];\n  \n  \treturn mapping;\n}\n\n@end\n```\n\n\u003e IMPORTANT: `FEMMapping.rootPath` is ignore during relationship mapping. Use `FEMRelationship.keyPath` instead!\n\n## Uniquing\nIt is a common case when you're deserializing JSON into CoreData and don't want to duplicate data in your database. This can be easily achieved by utilizing `FEMMapping.primaryKey`. It informs `FEMDeserializer` to track primary keys and avoid data copying. For example lets make Person's `email` a primary key attribute: \n```objective-c\n@implementation Person (Mapping)\n\n+ (FEMMapping *)defaultMapping {\n    FEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@\"Person\"];\n    mapping.primaryKey = @\"email\";\n    [mapping addAttributesFromArray:@[@\"name\"]];\n    [mapping addAttributesFromDictionary:@{@\"email\": @\"user_email\"}];\n\n    [mapping addRelationshipMapping:[Car defaultMapping] forProperty:@\"car\" keyPath:@\"car\"];\n    \n    return mapping;\n}\n\n@end\n```\n\n\u003e We recommend to index your primary key in datamodel to speedup keys lookup. Supported values for primary keys are Strings and Integers.\n\nStarting from second import `FEMDeserializer` will update existing `Person`. \n\n### Relationship bindings by PK\nSometimes object representation contains a relationship described by a PK of the target entity:\n```\n{\n\t\"result\": {\n\t\t\"id\": 314\n\t\t\"title\": \"https://github.com\"\n\t\t\"category\": 4\n\t}\n}\n```\nAs you can see, from JSON we have two objects: `Website` and `Category`. If `Website` can be imported easily, there is an external reference to a `Category` represented by its primary key `id`. Can we bind the `Website` to the corresponding category? Yep! We just need to treat Website's representation as a Category:\n\nFirst of all let’s declare our classes:\n```objective-c\n@interface Website: NSManagedObject\n\n@property (nonatomic, strong) NSNumber *identifier;\n@property (nonatomic, strong) NSString *title;\n@property (nonatomic, strong) Category *category;\n\n@end\n\n@interface Category: NSManagedObject\n\n@property (nonatomic, strong) NSNumber *identifier;\n@property (nonatomic, strong) NSString *title;\n@property (nonatomic, strong) NSSet *websites\n\n@end\n```\n\nNow it is time to define mapping for `Website`:\n\n```objective-c\n@implementation Website (Mapping)\n\n+ (FEMMapping *)defaultMapping {\n\tFEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@\"Website\"];\n\tmapping.primaryKey = @\"identifier\";\n\t[mapping addAttributesFromDictionary:@{@\"identifier\": @\"id\", @\"title\": @\"title\"}];\n\n\tFEMMapping *categoryMapping = [[FEMMapping alloc] initWithEntityName:@\"Category\"];\n\tcategoryMapping.primaryKey = @\"identifier\";\n\t[categoryMapping addAttributesFromDictionary:@{@\"identifier\": @\"category\"}];\n\n\t[mapping addRelationshipMapping:categoryMapping property:@\"category\" keyPath:nil];\n\n\treturn mapping;\n}\n\n@end\n\n```\n\nBy specifying `nil` as a `keyPath` for the category `Website`'s representation is treated as a `Category` at the same time. In this way it is easy to bind objects that are passed by PKs (which is quite common for network). \n\n### Weak relationship\nIn the example above there is an issue: what if our database doesn't contain `Category` with `PK = 4`? By default `FEMDeserializer` creates new objects during deserialization lazily. In our case this leads to insertion of `Category` instance without any data except `identifier`. In order to prevent such inconsistencies we can set `FEMRelationship.weak` to `YES`:\n\n```objective-c\n@implementation Website (Mapping)\n\n+ (FEMMapping *)defaultMapping {\n    FEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@\"Website\"];\n    mapping.primaryKey = @\"identifier\";\n    [mapping addAttributesFromDictionary:@{@\"identifier\": @\"id\", @\"title\": @\"title\"}];\n\n    FEMMapping *categoryMapping = [[FEMMapping alloc] initWithEntityName:@\"Category\"];\n    categoryMapping.primaryKey = @\"identifier\";\n    [categoryMapping addAttributeWithProperty:@\"identifier\" keyPath:nil];\n\n    FEMRelationship *categoryRelationship = [[FEMRelationship alloc] initWithProperty:@\"category\" keyPath:@\"category\" mapping:categoryMapping];\n    categoryRelationship.weak = YES;\n\n    [mapping addRelationship:categoryRelationship];\n\n    return mapping;\n}\n\n@end\n\n```\nAs a result it'll bind the `Website` with the corresponding `Category` only if the latter exists.\n\n## Delegation\nYou can customize deserialization process by implementing `FEMDeserializerDelegate` protocol:\n```objective-c\n@protocol FEMDeserializerDelegate \u003cNSObject\u003e\n\n@optional\n- (void)deserializer:(nonnull FEMDeserializer *)deserializer willMapObjectFromRepresentation:(nonnull id)representation mapping:(nonnull FEMMapping *)mapping;\n- (void)deserializer:(nonnull FEMDeserializer *)deserializer didMapObject:(nonnull id)object fromRepresentation:(nonnull id)representation mapping:(nonnull FEMMapping *)mapping;\n\n- (void)deserializer:(nonnull FEMDeserializer *)deserializer willMapCollectionFromRepresentation:(nonnull NSArray *)representation mapping:(nonnull FEMMapping *)mapping;\n- (void)deserializer:(nonnull FEMDeserializer *)deserializer didMapCollection:(nonnull NSArray *)collection fromRepresentation:(nonnull NSArray *)representation mapping:(nonnull FEMMapping *)mapping;\n\n@end\n```\n\nHowever, if you're using Delegate you also have to instantiate `FEMDeserializer` manually:\n##### NSObject \n```objective-c\nFEMDeserializer *deserializer = [[FEMDeserializer alloc] init];\ndeserializer.delegate = self;\n```\n\n##### NSManagedObject\n```objective-c\nFEMDeserializer *deserializer = [[FEMDeserializer alloc] initWithContext:managedObjectContext];\ndeserializer.delegate = self;\n```\n\nNote, that delegate methods will be called on every object and collection during deserialization. Lets use `Person` example:\n```\n{\n    \"name\": \"Lucas\",\n    \"user_email\": \"lucastoc@gmail.com\",\n    \"phones\": [\n        {\n            \"ddi\": \"55\",\n            \"ddd\": \"85\",\n            \"number\": \"1111-1111\"\n        }\n    ]\n}\n```\n\nMapping:\n```objective-c\n@implementation Person (Mapping)\n\n+ (FEMMapping *)defaultMapping {\n    FEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@\"Person\"];\n    [mapping addAttributesFromArray:@[@\"name\"]];\n    [mapping addAttributesFromDictionary:@{@\"email\": @\"user_email\"}];\n    [mapping addToManyRelationshipMapping:[Person defaultMapping] forProperty:@\"phones\" keyPath:@\"phones\"];\n\n    return mapping;\n}\n\n@end\n\n@implementation Phone (Mapping)\n\n+ (FEMMapping *)defaultMapping {\n    FEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@\"Phone\"];\n    [mapping addAttributesFromArray:@[@\"number\", @\"ddd\", @\"ddi\"]];\n\n    return mapping;\n}\n\n@end\n```\nDuring deserialization of persons collection order will be the following:\n\n1. willMapCollectionFromRepresentation:`Persons Array` mapping:`Person mapping`\n2. willMapObjectFromRepresentation:`Person Dictionary` mapping:`Person mapping`\n3. willMapCollectionFromRepresentation:`Phones Array` mapping:`Phone mapping`\n4. willMapObjectFromRepresentation:`Phone Dictionary` mapping:`Phone mapping`\n5. didMapObject:`Phone instance` fromRepresentation:`Phone Dictionary` mapping:`Phone mapping`\n6. didMapObject:`Person instance` fromRepresentation:`Person Dictionary` mapping:`Person mapping`\n7. didMapCollection:`Persons instances Array` fromRepresentation:`Persons Array` mapping:`Person mapping`\n\n# Thanks\n* Special thanks to [lucasmedeirosleite](https://github.com/lucasmedeirosleite) for amazing framework.\n\n# Extra\nRead out [blogpost](https://yalantis.com/blog/from-json-to-core-data-fast-and-effectively/) about FastEasyMapping.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FYalantis%2FFastEasyMapping","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FYalantis%2FFastEasyMapping","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FYalantis%2FFastEasyMapping/lists"}