A super fast & convenient object mapper tailored for your needs

Related tags

Networking Tailor
Overview

Tailor Swift logo

CI Status Version Carthage Compatible License Platform Documentation Swift

A super fast & convenient object mapper tailored for your needs.

Mapping objects to arrays or dictionaries can be a really cumbersome task, but those days are over. Tailor features a whole bunch of nifty methods for your model sewing needs.

Mapping properties

Tailor features property, relation(s) mapping for both struct and class objects.

Struct

struct Person: Mappable {

  var firstName: String? = ""
  var lastName: String? = ""

  init(_ map: [String : Any]) {
    firstName <- map.property("first_name")
    lastName  <- map.property("last_name")
  }
}

let dictionary = ["first_name" : "Taylor", "last_name" : "Swift"]
let model = Person(dictionary)

Class

class Person: Mappable {

  var firstName: String? = ""
  var lastName: String? = ""

  required convenience init(_ map: [String : AnyObject]) {
    self.init()
    firstName <- map.property("first_name")
    lastName  <- map.property("last_name")
  }
}

let dictionary = ["first_name" : "Taylor", "last_name" : "Swift"]
let model = Person(dictionary)

Mapping objects

struct Person: Mappable {

  var firstName: String? = ""
  var lastName: String? = ""
  var spouse: Person?
  var parents = [Person]()

  init(_ map: [String : Any]) {
    firstName <- map.property("first_name")
    lastName  <- map.property("last_name")
    spouse    <- map.relation("spouse")
    parents   <- map.relations("parents")
  }
}

let dictionary = [
  "first_name" : "Taylor",
  "last_name" : "Swift",
  "spouse" : ["first_name" : "Calvin",
              "last_name" : "Harris"],
  "parents" : [
             ["first_name" : "Andrea",
              "last_name" : "Swift"],
              ["first_name" : "Scott",
              "last_name" : "Swift"]
  ]
]
let model = Person(dictionary)

SafeMappable

struct ImmutablePerson: SafeMappable {
  let firstName: String
  let lastName: String
  let spouse: Person
  let parents = [Person]()

  init(_ map: [String : Any]) throws {
    firstName = try map.property("firstName").unwrapOrThrow()
    lastName = try map.property("lastName").unwrapOrThrow()
    spouse = try map.relationOrThrow("spouse").unwrapOrThrow()
    parents = try map.relationsOrThrow("parents").unwrapOrThrow()
  }
}

let immutablePerson: ImmutablePerson
do {
  immutablePerson = try TestImmutable(["firstName" : "foo" , "lastName" : "bar"])
} catch {
  print(error)
}

Transforms

NSDate? in let dateFormatter = NSDateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" return dateFormatter.dateFromString(value) }) } } let dictionary = [ "first_name" : "Taylor", "last_name" : "Swift", "spouse" : ["first_name" : "Calvin", "last_name" : "Harris"], "parents" : [ ["first_name" : "Andrea", "last_name" : "Swift"], ["first_name" : "Scott", "last_name" : "Swift"] ], "birth_date": "1989-12-13" ] let model = Person(dictionary)">
struct Person: Mappable {

  var firstName: String? = ""
  var lastName: String? = ""
  var spouse: Person?
  var parents = [Person]()
  var birthDate = NSDate?

  init(_ map: [String : Any]) {
    firstName <- map.property("first_name")
    lastName  <- map.property("last_name")
    spouse    <- map.relation("spouse")
    parents   <- map.relations("parents")
    birthDate <- map.transform("birth_date", transformer: { (value: String) -> NSDate? in
      let dateFormatter = NSDateFormatter()
      dateFormatter.dateFormat = "yyyy-MM-dd"
      return dateFormatter.dateFromString(value)
    })
  }
}

let dictionary = [
  "first_name" : "Taylor",
  "last_name" : "Swift",
  "spouse" : ["first_name" : "Calvin",
              "last_name" : "Harris"],
  "parents" : [
             ["first_name" : "Andrea",
              "last_name" : "Swift"],
              ["first_name" : "Scott",
              "last_name" : "Swift"]
  ],
  "birth_date": "1989-12-13"
]
let model = Person(dictionary)

KeyPath

Tailor supports mapping values using deep keyPath

struct Book: Mappable {

  var title: String = ""
  var publisherName: String = ""
  var authorName: String = ""
  var firstReviewerName: String = ""

  init(_ map: [String : Any]) {
    title <- map.resolve(keyPath: "title")
    publisherName <- map.resolve(keyPath: "publisher.name")
    authorName <- map.resolve(keyPath: "info.author.name")
    firstReviewerName <- map.resolve(keyPath: "meta.reviewers.0.info.name.first_name")
  }
}

Resolving value types.

Tailor supports mapping values from dictionaries using type specific functions.

dictionary.boolean("key")
dictionary.double("key")
dictionary.float("key")
dictionary.int("key")
dictionary.string("key")

You can also use value(forKey:ofType:), it works like this.

dictionary.value(forKey: "key", ofType: Bool.self)
dictionary.value(forKey: "key", ofType: Double.self)
dictionary.value(forKey: "key", ofType: Float.self)
dictionary.value(forKey: "key", ofType: Int.self)
dictionary.value(forKey: "key", ofType: String.self)

All of these methods returns an optional value.

Installation

Tailor is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Tailor'

Contribute

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create pull request

Who made this?

Comments
  • Improve mapping immutable objects

    Improve mapping immutable objects

    This PR tries to address the issue where you want to map properties to an immutable model.

    SafeMappable protocol

    public protocol SafeMappable {
      init(_ map: JSONDictionary) throws
    }
    

    The new SafeMappable protocol can be used for mapping immutable models.

    Usage

    struct TestImmutable: SafeMappable {
      var firstName: String
      var lastName: String
    
      init(_ map: JSONDictionary) throws {
        firstName = try <-map.property("firstName")
        lastName = try <-map.property("lastName")
      }
    }
    

    This PR also has some breaking changes; object and objects have been replaced by property and properties. This change was made because I felt that it was more semantically correct.

    tl;dr

    • [x] Rename object() to property()
    • [x] Rename objects() to properties()
    • [x] Split source in to separate files
    • [x] Introduce prefix operator <-
    • [x] Add SafeMappable protocol
    • [x] Add propertyOrThrow in Dictionary extension
    • [x] Refactor code style
    • [x] Remove inspectable

    Tries to fix https://github.com/zenangst/Tailor/issues/23

    opened by zenangst 9
  • Add PathAccessible for easy accessing through path with key and index

    Add PathAccessible for easy accessing through path with key and index

    So that we can use it like

    self.secret <- map.path(["chaos", 1, "way", "light", 1])?.property("secret")
    

    Initially, I want to use variadic parameter instead of array, but it seems to not work with these LiteralConvertible https://github.com/onmyway133/issues/issues/133

    opened by onmyway133 7
  • Improve resolving paths

    Improve resolving paths

    This PR aims to improve the usability of resolving key paths.

    With this pull request you can resolve nested paths like this;

    XCTAssertEqual(json.path("school.clubs.0.detail.name"), "DC")
        XCTAssertEqual(json.path("school.clubs.0.detail.people.0.first_name"), "Clark")
        XCTAssertEqual(json.path("school.clubs.0.detail.people.0.age"), 78)
        XCTAssertEqual(json.path("school.clubs.0.detail.people")!, [
          [
            "first_name": "Clark",
            "last_name": "Kent",
            "age" : 78
          ],
          [
            "first_name": "Bruce",
            "last_name": "Wayne",
            "age" : 77
          ]
          ])
    

    It can achieve this with the refactoring done in PathAccessible to introduce method overloading for the path method.

    opened by zenangst 5
  • Simple assignment

    Simple assignment

    For now, we use <- which requires that the variable to be declared as var and has initial values, like

    struct Person: Mappable {
          var name: String = ""
    
          init(_ map: JSONDictionary) {
            self.name <- map.path(["info"])?.property("name")
          }
    }
    

    How about having something like parse with DefaultType protocol, so that correct or default value is returned. parse will unwrap optional or return default value. It can be written as postfix operator

    struct Person: Mappable {
          let name: String // 😬
    
          init(_ map: JSONDictionary) {
            self.name = parse(map.path(["info"])?.property("name"))
          }
    }
    
    opened by onmyway133 3
  • Improve/mapping default types

    Improve/mapping default types

    This adds methods for mapping double, float, int and string. When mapping a type, if it cannot be resolved directly, it will now try to resolve it as the closest type available.

    If you map a Float but get a Double, Tailor will try to make a Float out of the Double before returning.

    opened by zenangst 2
  • Make Tailor to work with immutable non-optional types

    Make Tailor to work with immutable non-optional types

    Let's say I have an immutable model (which I do have often, and it's a good think to do :smiley: )

    struct Person {
    
      let firstName: String
      let lastName: String
    }
    
    let p = Person(firstName: "Sarah ", lastName: "Connor")
    

    Now I want to use Tailor Mapper to map my JSON to the Person type

    extension Person: Mappable {
      init(_ map: JSONDictionary) {
        firstName <- map.property("first_name")
        lastName  <- map.property("last_name")
      }
    }
    
    let dictionary = ["first_name" : "Sarah", "last_name" : "Connor"]
    let model = Person(dictionary)
    

    In that way you can first start with making models and using them directly. After that you can add Mapping support without breaking ability to directly instantiate your Person model

    opened by kostiakoval 2
  • Throw using optional

    Throw using optional

    • Remove all the orThrow method. This adds unwrapOrThrow on optional. So this is more like Optional -> Throw. We now don't need to have 2 methods
    • Remove some custom operators. We don't really need these
    • Also, re-indent all the test files to use 2 spaces
    opened by onmyway133 1
  • Improve/resolving paths part deux

    Improve/resolving paths part deux

    This PR aims to bring a unified and clear public API, now you can resolve keys and key paths using resolve(keyPath:).

    Instead of

    json.path("school.clubs.1.detail")?.property("name")
    

    You can now write;

    json.resolve(keyPath: "school.clubs.1.detail.name")
    

    path has been marked as deprecated.

    opened by zenangst 1
  • Boolean properties

    Boolean properties

    class DynamicModelSubTitle: Mappable, CustomStringConvertible {
    
        var title: String? = ""
        var subTitle: String? = ""
        var tag: String? = ""
        var action: String? = ""
        var showAccessory = false
    
        required convenience init(_ map: [String : AnyObject]) {
            self.init()
            title <- map.property("title")
            subTitle <- map.property("sub_title")
            tag <- map.property("tag")
            action <- map.property("action")
    
    
        }
    }
    

    with JSON

                {
                    "kind":"subTitle",
                    "title":"Bank Of America",
                    "sub_title":"ACCOUNT # XXXX-1234",
                    "tag": "my tag",
                    "accessory": true,
                    "action":"open:AddBank"
                },
    

    How do I map accessory to the showAccessory property?

    opened by navisingh 1
  • Support defaultValue

    Support defaultValue

    There are cases that users just want struct with let declaration. Previously, we have to declare var for <- to work. This just uses simple assignment with default value

    • Add DefaultType for type that has default value
    • Add <? operator to fall back to default value
    struct Book: Mappable {
      let name: String
      let pageCount: Int
      let website: NSURL?
    
      init(_ map: JSONDictionary) {
        name = <?map.property("name")
        pageCount = <?map.property("page_count")
        website = map.transform("website_url", transformer: NSURL.init(string: ))
      }
    }
    
    opened by onmyway133 1
  • Hierarchy Type

    Hierarchy Type

    There are cases like GitHub API https://github.com/onmyway133/Github.swift/tree/master/Sources/Classes/Event where we want to parse and return corresponding subclasses instead, so this PR supports that 😬

    opened by onmyway133 1
  • Deserialize an object to JSON string

    Deserialize an object to JSON string

    Does this library allow to maintain the order of the attributes when deserializing an object to a JSON string? This feature is important for me, since I need to create and compare hashes of JSON strings.

    Thanks

    opened by lmsmartins 0
  • Performance benchmark comparisons

    Performance benchmark comparisons

    Hi, I would like to know if you have any performance benchmarks in comparisons to other popular libraries for reference, since your tag-line stated 'A super fast & convenient object mapper'?

    opened by francisykl 2
Releases(3.0.0)
Owner
Christoffer Winterkvist
random hero at @finkoslo by day, cocoa vigilante by night, dad at dawn. my life is awesome. Previously @hyperoslo
Christoffer Winterkvist
Super lightweight async HTTP server library in pure Swift runs in iOS / MacOS / Linux

Embassy Super lightweight async HTTP server in pure Swift. Please read: Embedded web server for iOS UI testing. See also: Our lightweight web framewor

Envoy 540 Dec 15, 2022
Super lightweight web framework in Swift based on SWSGI

Ambassador Super lightweight web framework in Swift based on SWSGI Features Super lightweight Easy to use, designed for UI automatic testing API mocki

Envoy 170 Nov 15, 2022
Fast Websockets in Swift for iOS and OSX

SwiftWebSocket Conforming WebSocket (RFC 6455) client library for iOS and Mac OSX. SwiftWebSocket passes all 521 of the Autobahn's fuzzing tests, incl

Josh 1.5k Dec 28, 2022
A minimal, fast and unopinionated web framework for Swift

![Fire Image] (http://i.imgur.com/1qR6Nl4.png) Blackfire An extremely fast Swift web framework ?? Getting Started If you're familiar with express.js t

Elliott Minns 908 Dec 2, 2022
A communication channel from your Mac to your watch.

Stargate A communication channel from your Mac to your watch. Providing a convenient wrapper around MMWormhole and PeerKit, Stargate leverages Multipe

Contentful 135 Jun 29, 2022
StatusBarOverlay will automatically show a "No Internet Connection" bar when your app loses connection, and hide it again. It supports apps which hide the status bar and The Notch

StatusBarOverlay StatusBarOverlay will automatically show a "No Internet Connection" bar when your app loses connection, and hide it again. It support

Idle Hands Apps 160 Nov 2, 2022
Another network wrapper for URLSession. Built to be simple, small and easy to create tests at the network layer of your application.

Another network wrapper for URLSession. Built to be simple, small and easy to create tests at the network layer of your application. Install Carthage

Ronan Rodrigo Nunes 89 Dec 26, 2022
This generic SOAP client allows you to access web services using a your iOS app, Mac OS X app and AppleTV app.

This generic SOAP client allows you to access web services using a your iOS app, Mac OS X app and Apple TV app. With this Framework you can create iPh

Prioregroup.com 479 Nov 22, 2022
Powering your RAC architecture

Intro Most applications out there follow the same pattern: Is T persisted and has not expired? Yes: Use it ✅ No: Fetch T from the network 1. Do we hav

Rui Peres 186 Jun 22, 2022
Get your device ip address, router ip or wifi ssid

FGRoute FGRoute is written on C and Objective C (includes Swift support), it helps developers to get rid of dealing with WiFi interfaces. Example To r

Arthur Sahakyan 137 Dec 5, 2022
Setup your class structure in Xcode Interface Builder and save() in Parse Server.

ISParseBind With ISParseBind you can save, update and query PFObjects using the power of Xcode Interface Builder resources. https://www.youtube.com/wa

Weni 10 Mar 28, 2022
iOS client for the Brewfactory project - brew your own beer

BrewMobile iOS client for the Brewfactory project. Read the stories of upgrading BrewMobile to ReactiveCocoa & Swift on AllTheFlow. What is this? App

brewfactory 195 Dec 18, 2022
A remote for your IR devices for iOS and Mac!

Command your TV, Apple TV or Receiver with your Mac/iOS device through iTach. Screenshots On iOS: On Mac (notification center): How to use Buy a iTach

Michael Villar 19 Nov 4, 2022
The fastest iOS app to add a note to your email inbox

Major Key How often are you on the run, or hanging out with friends, only to suddenly think of this really important thing you need to do when you're

Felix Krause 190 Oct 9, 2022
An iOS app for communicating with your clightning node over the lightning network

An iOS app for communicating with your clightning node over the lightning network

William Casarin 18 Dec 14, 2022
VFNetwork is a protocol-oriented network layer that will help you assemble your requests in just a few steps.

Simple, Fast and Easy. Introduction VFNetwork is a protocol-oriented network layer that will help you assemble your requests in just a few steps. How

Victor Freitas 4 Aug 22, 2022
iOS app for monitoring and controlling your Tesla vehicles.

Teslawesome This is an unofficial iOS app for monitoring and controling your Tesla vehicles. The purpose of being open sourced is just for more visibi

Ivaylo Gashev 2 Oct 14, 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
An unofficial wrapper around FSEvent tailored for Swift 5.

EonilFSEvents Eonil 2018 Maintenance. 2019 Maintenance. It's possible to use FSEvents directly in Swift, but it still involves many boilerplate works

eonil 87 Dec 24, 2022
Simple and Elegant Range(A,B) to Range(P,Q) mapper in less then five lines of code.

HSRange Description HSRangeConvertor Simple and Elegant Range[A,B] to Range[P,Q] mapper in less then three lines of code. E.g. Suppose we have Range[1

Hitendra Hckr 10 Sep 29, 2021