{"id":1709,"url":"https://github.com/krzysztofzablocki/PropertyMapper","last_synced_at":"2025-08-02T04:32:19.565Z","repository":{"id":9689732,"uuid":"11636706","full_name":"krzysztofzablocki/PropertyMapper","owner":"krzysztofzablocki","description":"Property mapping for Objective-C iOS apps.","archived":false,"fork":false,"pushed_at":"2021-01-06T15:38:40.000Z","size":1315,"stargazers_count":1124,"open_issues_count":3,"forks_count":81,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-07-28T08:45:30.996Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://merowing.info","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"realm/realm-cocoa","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/krzysztofzablocki.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":"Funding.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"krzysztofzablocki"}},"created_at":"2013-07-24T14:27:16.000Z","updated_at":"2025-07-18T01:00:06.000Z","dependencies_parsed_at":"2022-09-24T05:51:42.833Z","dependency_job_id":null,"html_url":"https://github.com/krzysztofzablocki/PropertyMapper","commit_stats":null,"previous_names":["krzysztofzablocki/kzpropertymapper"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/krzysztofzablocki/PropertyMapper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krzysztofzablocki%2FPropertyMapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krzysztofzablocki%2FPropertyMapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krzysztofzablocki%2FPropertyMapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krzysztofzablocki%2FPropertyMapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/krzysztofzablocki","download_url":"https://codeload.github.com/krzysztofzablocki/PropertyMapper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krzysztofzablocki%2FPropertyMapper/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268283448,"owners_count":24225308,"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-01T02:00:08.611Z","response_time":67,"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":[],"created_at":"2024-01-05T20:15:53.946Z","updated_at":"2025-08-02T04:32:19.135Z","avatar_url":"https://github.com/krzysztofzablocki.png","language":"Objective-C","funding_links":["https://github.com/sponsors/krzysztofzablocki"],"categories":["Parsing","HarmonyOS","Objective-C","etc"],"sub_categories":["JSON","Other free courses","Windows Manager"],"readme":"[![CI Status](http://img.shields.io/travis/krzysztofzablocki/KZPropertyMapper.svg?style=flat)](https://travis-ci.org/krzysztofzablocki/KZPropertyMapper)\n[![codecov](https://codecov.io/gh/krzysztofzablocki/KZPRopertyMapper/branch/master/graph/badge.svg)](https://codecov.io/gh/krzysztofzablocki/KZPRopertyMapper)\n[![Version](https://img.shields.io/cocoapods/v/KZPropertyMapper.svg?style=flat)](http://cocoapods.org/pods/KZPropertyMapper)\n[![License](https://img.shields.io/cocoapods/l/KZPropertyMapper.svg?style=flat)](http://cocoapods.org/pods/KZPropertyMapper)\n[![Platform](https://img.shields.io/cocoapods/p/KZPropertyMapper.svg?style=flat)](http://cocoapods.org/pods/KZPropertyMapper)\n\n# Stop repeating  your data parsing code in iOS apps.\nData parsing is one of most common tasks we need to do in our apps, yet still majority of people do this parsing by hand, always repeating the same code for each class they need to map.\n\nUsual parsing requires this steps:\n* make sure you translate NSNull to nil and not crash\n* gracefully handle optional params\n* do type conversions\n* data format validation\n\n## Why Property Mapper?\nThere are libraries helping with that like Mantle, RESTKit and many more… But I wanted something that's self contained, easy to change / remove and requires minimal amount of code.\n\nI've created **Property Mapper** as part of working on [Foldify][2], a simple self contained solution that allows you to specify mapping between data you receive and data representation you have in your application... with some additional features, like **type boxing**, **validation**.\n\nI don't like passing around JSON so I write parsing on top of native objects like NSDictionary/NSArray.\nIf you get data as JSON just write a simple category that transforms JSON to native objects using NSJSONSerialization.\n\n## Example usage\nLet's assume you have object like this:\n````objc\n@interface TestObject : NSObject\n@property(nonatomic, strong) NSURL *contentURL;\n@property(nonatomic, strong) NSURL *videoURL;\n@property(nonatomic, strong) NSNumber *type;\n@property(nonatomic, strong) NSString *title;\n@property(nonatomic, strong) NSString *uniqueID;\n\n@end\n````\n\nand you receive data from server in this format:\n````objc\n@{\n  @\"videoURL\" : @\"http://test.com/video.mp4\",\n\t@\"name\" : @\"Some Cool Video\",\n\t@\"videoType\" : [NSNull null],\n\t@\"sub_object\" : @{\n\t\t\t@\"title\" : @616,\n\t\t\t@\"arbitraryData\" : @\"data\"\n\t}\n}\n````\nthis is the code you would write in your parsing code:\n````objc\n[KZPropertyMapper mapValuesFrom:dictionary toInstance:self usingMapping:@{\n   @\"videoURL\" : KZBox(URL, contentURL),\n     @\"name\" : KZProperty(title),\n     @\"videoType\" : KZProperty(type),\n     @\"sub_object\" : @{\n         @\"title\" : KZProperty(uniqueID)\n         }\n\n  }];\n````\nQuite obvious what it does but in case you are confused, it will translate videoURL string to contentURL NSURL object, it will also grab title from sub_object and assign it to uniqueID. It also handles NSNull.\n\n## Advanced usage\nLet's now change our mind and decide that we want our type property to be typedef enumeration, it's quite easy with KZPropertyMapper, change type mapping to following and add following method:\n````objc\n@\"videoType\" : KZCall(videoTypeFromString:, type),\n\n//! implemented on instance you are parsing\n- (id)videoTypeFromString:(NSString *)type\n{\n  if ([type isEqualToString:@\"shortVideo\"]) {\n    return @(VideoTypeShort);\n  }\n\n  return @(VideoTypeLong);\n}\n````\n\nIf you need property name being passed while using selectors, just pass two-argument selector in KZCall. Second argument will be property name passed as NSString.\n````objc\n@\"video\" : KZCall(objectFromDictionary:forPropertyName:, type),\n\n//! implemented on instance you are parsing\n- (id)objectFromDictionary:(NSDictionary *)dictionary forPropertyName:(NSString *)propertyName\n{\n  Class objectClass = [self classForProperty:propertyName];\n  id object = [objectClass new];\n  [object updateFromDictionary:dictionary];\n  return object;\n}\n````\n\n\nDone. KVC should also take care of escaping NSNumber into int if your property uses primitive type. Same approach will work for sub-object instances or anything that you can assign to property.\n\n## Validations\nYou can also validate your server data before mapping it:\n````objc\n[KZPropertyMapper mapValuesFrom:dictionary toInstance:self usingMapping:@{\n    @\"videoURL\" : KZBox(URL, contentURL).isRequired().min(10),\n    @\"name\" : KZProperty(title).lengthRange(5, 12),\n    @\"videoType\" : KZProperty(type),\n    @\"sub_object\" : @{\n      @\"title\" : KZProperty(uniqueID),\n    },\n  }];\n````\nValidators can be chained together, you can specify as many as you wish for each field, validation happens on source data before mapping happens.\n\nIf validation fails mapValues will return NO as a result, and you can use expanded method to get list of validation errors.\n\nAny validation errors will prevent mapping, as data might be corrupted and we don't want partially updated data.\n\n### Built-in validations\n#### Strings\n* isRequired\n* matchesRegEx\n* length\n* minLength\n* maxLength\n* lengthRange\n* oneOf\n* equalTo\n\n#### Numbers\n* min\n* max\n* range\n\nIf you want more you can add validations as categories on KZPropertyDescriptor, check sample code to see how it's done, it's extremely simple.\n\n### Referencing arrays items\nIf your data comes to you in ordered array instead of dictionaries you can reference that as well:\n````objc\nsourceData = @{@\"sub_object_array\" : @[@\"test\", @123]}\n\n@{@\"sub_object_array\" : @{@1 : KZProperty(uniqueID)}\n\n````\nThis will grab first item from sub_object_array and assign it to uniqueID. It also works recursively.\n\n\n### Expanding boxing capabilities\nYou can expand boxing capabilities across whole application easily, just add category on KZPropertyMapper that implements methods like this:\n````objc\n+ (id)boxValueAsType:(id)value\n{\n\t//! your boxing\n}\n````\nNow you can use @Type mapping everywhere in your code.\n\n\n# Changelog\n\n## 2.5.0\n\n* Added KZList that allows you to map single source property into multiple target ones.\n* Added type checking while parsing, if mismatched type is found a property will be ignored and a warning will be generated.  \n* Fixed few minor bugs when working with unexpected server responses.\n\n````objc\n@{\n  \t@\"videoURL\" : KZList(\n\t\t\t\tKZBoxT(object, URL, contentURL),\n\t\t\t\tKZPropertyT(object, uniqueID),\n\t\t\t\tKZCallT(object, passthroughMethod:, type)\n\t\t\t)\n}\n````\n\nContributed by [Marek Cirkos][3]\n\n## 2.0\n* New property syntax (old one still works) that allows you to get  compile errors when you misspell property names.\n* Introduced concept of validators, chain-able.\n\nTime to implement this changes was sponsored by [The App Business][1].\n\n# Installing\n- Using CocoaPods: Add the following line to your `Podfile`:\n\n    ```pod \"KZPropertyMapper\"```\n\n- Using Carthage: Add the following to your `Cartfile`:\n\n    ```github \"krzysztofzablocki/KZPropertyMapper\" \"master\"```\n\n- Or just add the `KZPropertyMapper/` folder to your project, making sure you enable ARC on these files.\n\n# Final note\nUnit tests should serve as documentation. Default boxing types include @URL and @Date.\n\n[Follow me on twitter][7]\n\n [1]: http://theappbusiness.com\n [2]: http://foldifyapp.com\n [3]: https://github.com/marekcirkos\n [7]: http://twitter.com/merowing_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrzysztofzablocki%2FPropertyMapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkrzysztofzablocki%2FPropertyMapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrzysztofzablocki%2FPropertyMapper/lists"}