Git Product home page Git Product logo

mapper's Introduction

Mapper

Mapper is a simple Swift library to convert JSON to strongly typed objects. One advantage to Mapper over some other libraries is you can have immutable properties.

Installation

use_frameworks!

pod "ModelMapper"
github "lyft/mapper"

Usage

Simple example:

import Mapper
// Conform to the Mappable protocol
struct User: Mappable {
  let id: String
  let photoURL: URL?

  // Implement this initializer
  init(map: Mapper) throws {
    try id = map.from("id")
    photoURL = map.optionalFrom("avatar_url")
  }
}

// Create a user!
let JSON: NSDictionary = ...
let user = User.from(JSON) // This is a 'User?'

Using with enums:

enum UserType: String {
  case Normal = "normal"
  case Admin = "admin"
}

struct User: Mappable {
  let id: String
  let type: UserType

  init(map: Mapper) throws {
    try id = map.from("id")
    try type = map.from("user_type")
  }
}

Nested Mappable objects:

struct User: Mappable {
  let id: String
  let name: String

  init(map: Mapper) throws {
    try id = map.from("id")
    try name = map.from("name")
  }
}

struct Group: Mappable {
  let id: String
  let users: [User]

  init(map: Mapper) throws {
    try id = map.from("id")
    users = map.optionalFrom("users") ?? []
  }
}

Use Convertible to transparently convert other types from JSON:

extension CLLocationCoordinate2D: Convertible {
  public static func fromMap(_ value: Any) throws -> CLLocationCoordinate2D {
    guard let location = value as? NSDictionary,
      let latitude = location["lat"] as? Double,
      let longitude = location["lng"] as? Double else
      {
         throw MapperError.convertibleError(value: value, type: [String: Double].self)
      }

      return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
  }
}

struct Place: Mappable {
  let name: String
  let location: CLLocationCoordinate2D

  init(map: Mapper) throws {
    try name = map.from("name")
    try location = map.from("location")
  }
}

let JSON: NSDictionary = [
  "name": "Lyft HQ",
  "location": [
    "lat": 37.7603392,
    "lng": -122.41267249999999,
  ],
]

let place = Place.from(JSON)

Custom Transformations

private func extractFirstName(object: Any?) throws -> String {
  guard let fullName = object as? String else {
    throw MapperError.convertibleError(value: object, type: String.self)
  }

  let parts = fullName.characters.split { $0 == " " }.map(String.init)
  if let firstName = parts.first {
    return firstName
  }

  throw MapperError.customError(field: nil, message: "Couldn't split the string!")
}

struct User: Mappable {
  let firstName: String

  init(map: Mapper) throws {
    try firstName = map.from("name", transformation: extractFirstName)
  }
}

Parse nested or entire objects

struct User: Mappable {
  let name: String
  let JSON: AnyObject

  init(map: Mapper) throws {
    // Access the 'first' key nested in a 'name' dictionary
    try name = map.from("name.first")
    // Access the original JSON (maybe for use with a transformation)
    try JSON = map.from("")
  }
}

See the docstrings and tests for more information and examples.

Open Radars

These radars have affected the current implementation of Mapper

  • rdar://23376350 Protocol extensions with initializers do not work in extensions
  • rdar://23358609 Protocol extensions with initializers do not play well with classes
  • rdar://23226135 Can't conform to protocols with similar generic function signatures
  • rdar://23147654 Generic functions are not differentiated by their ability to throw
  • rdar://23695200 Using the ?? operator many times is unsustainable.
  • rdar://23697280 Lazy collection elements can be evaluated multiple times.
  • rdar://23718307 Non final class with protocol extensions returning Self don't work

License

Mapper is maintained by Lyft and released under the Apache 2.0 license. See LICENSE for details

mapper's People

Contributors

austinate avatar brodney avatar dduan avatar keith avatar lzell avatar prayagverma avatar rebello95 avatar ryan-lane avatar sunshinejr avatar yosuke-matsuda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mapper's Issues

Hold JSON as AnyObject in Mapper

Would you consider having Mapper hold JSON as an AnyObject?

All my server responses are wrapped in a 'data' field, like so:

{
    "data" : [
      {
        "username" : "user_a"
      },
      {
        "username" : "user_b"
      }
    ]
}

I then want to directly create an array of User (see below) from my response. Since I don't have an outer object (like Group in your example) that would have an array of this type, I created a static function like so:

struct User: Mappable {
  let username: String

  init(map: Mapper) throws {
      try username = map.from("username")
  }

  static func createFromServerData(data: [String: AnyObject]) -> Result<[User]> {
      do {
          return .Success(try Mapper(JSON: data).from("data"))
      } catch {
          return .Failure(.InvalidResponse)
      }
  }
}

However, I don't want to repeat "data" all over the place, so I would like to extract it at the network level. The problem is that for the above JSON, this would give me an array.. but Mapper wants to store it as a dictionary. When I use the

public func from<T: Mappable>(field: String) throws -> [T]

form like so:

try Mapper(JSON: data).from("")

the value returned from JSONFromField() would correctly be my array in an AnyObject and then it would be cast to an array of dictionaries... which would all work as expected.

If you were to implement this change, The wrinkle would be that in JSONFromField(), you would need to try to cast self.JSON as a dictionary (in order to call valueForKeyPath)?

What do you think?

Thank you.

Use of NSDictionary and NSArray in Mappable protocol

The Mappable protocol uses NSDictionary and NSArray in its convenience methods.

public static func from(_ JSON: NSDictionary) -> Self?
public static func from(_ JSON: NSArray) -> [Self]?

Since Swift continues to move away from Objective C with 3.0, I would propose to change the types toΒ [String: Any] and [Any]/[[String: Any]] so it integrates more naturally in Swift development. Or is there any good reason to prefer NSDictionary/NSArray over these?

[Question] Beta tag for podspec use

Hi,

I'm currently using mapper as a dependency in another pod.
This parent pod is merging to Swift 3.0

Could it be possible to pod repo push a tag like 5.0.0-beta and use it for swift-3.0 branch ?
That will help a lot for Swift 3.0 merging session.

Happy coding

Cheers From France

Is inheritance possible?

I was wondering if could subclass my models. Right now compiler throws an error about
protocol 'Mappable' requirement 'from' cannot be satisfied by a non-final class ('AdDetailModel') because it uses 'Self' in a non-parameter, non-result type position

JSON Serialization

Congratulations on open sourcing Mapper!

I'm comparing ObjectMapper to Lyft's Mapper. To me the only (and very important) difference is first-class support for non-optionals via failable initializers (which ObjectMapper kind of supports, but it's never been officially documented).

What Lyft's Mapper is really missing though is JSON serialization. Is that something that is on your timeline? If so, any idea of when it could be available?

New patch version.

Hey guys, after #134 was merged it would be awesome if you could release a new version of Mapper. It would ease up the commit requirement in Carthage that we have to use right now. Thanks!

Suggestion: Deserialization can handle wrong format in JSON

This is a suggestion to allow mapper to handle the case that sometimes the types from the server does not types we expect.

Fx sometimes we expect a double but the server sends a double as string.

This could be done by removing the extensions in "DefaultConvertible" and instead implement Extensions for numbers that conform to Convertible

fx

import Foundation
import Mapper

extension Double: Convertible {
    /// Create a Double from Mapper
    ///
    /// - parameter value: The object (or nil) passed from Mapper
    ///
    /// - throws: MapperError.convertibleError if the passed value is not a String
    /// - throws: MapperError.customError      if the passed value is a String but the Double initializer fails
    ///
    /// - returns: The created double
    public static func fromMap(_ value: Any) throws -> Double {

        if let double = value as? Double {
            return double
        }

        guard let string = value as? String else {
            throw MapperError.convertibleError(value: value, type: String.self)
        }

        guard let double = Double(string) else {
            throw MapperError.customError(field: nil, message: "'\(string)' is not a valid Double")
        }

        return double
    }
}

Also another suggestion could be that mapper does not care if variables are lowercase/uppercase or if camelcase is used but underscore naming is used.

Doubly nested arrays

Hi, been waiting to use mapper for a personal project for quite a while now and finally came around to doing so. Really loving it!

The only problem is that the API I'm working with is sending data as a doubly-nested array at one point. And I'm not quite sure how to work with this πŸ˜•

I've defined my model struct like this:

struct Building {
    // ...
    let points: [[CLLocationCoordinate2D]]
}

Deserializing like this unfortunately isn't working:

extension Building: Mappable {
    init(map: Mapper) throws {
        // ...
        try points = map.from("punkte")
    }
}

Is there a simple way to get around this? Should this be working and I'm missing something else?

Thanks for any help in advance 😊

null fields

Sorry, just a question. using optionalFrom throws Error when handling null fields. Shouldn't it return nil? Am I missing some point?

Issues when using firebase

I am using Swift 3 (may not upgrade to 4 for some reason) and ModelMapper 6.0.0. Everything was going fine until I try to add firebase. After adding firebase model mapper is throwing some error. e.g.
/Users/sayedmahmudulalam/insuree_user/Pods/ModelMapper/Sources/NSURL+Convertible.swift:13:24: Invalid redeclaration of 'fromMap'
/Users/sayedmahmudulalam/insuree_user/Pods/ModelMapper/Sources/URL+Convertible.swift:4:16: Redundant conformance of 'URL' to protocol 'Convertible'
/Users/sayedmahmudulalam/insuree_user/Pods/ModelMapper/Sources/URL+Convertible.swift:13:24: Invalid redeclaration of 'fromMap'

Can you please explain the reason or suggest some alternate version?

More descriptive MapperError

Understand that my implementation of Mappable init can throw any error I want, but was just seeing how receptive you would be to change along the following lines:

Would be nice to have an indication of which field caused the throw, possibly also an indication of why it was thrown. This would be a good way to get slightly more descriptive errors without having to implement custom throws from each call to mapper.from.

This change would potentially involve adding an associated message value to MapperError, something along the lines of:

public struct MapperError: ErrorType {
    case MapError(string)
    @warn_unused_result
    public init(message: String) {
       self = .MapError(message)
   }
}

Question: Is there any good patterns to avoid this common developer error?

So we've run into a few bugs where we're doing this:

  1. A Model, Model.swift is created with a bunch of required properties (non-optional)
  2. One of those properties is changed to be optional but the developer forgets to update the init method from .from to .optionalFrom and when we actually get a nil it crashes.

This can obviously be found with unit tests but is there any other ways of catching this?

Release 2.1.1

Would be awesome if you could release a minor version containing this commit: 4f74320 (Make transformations throw MissingFieldErrors)

Cheers!

optionalFrom vs try?

Just a question, I may be missing something obvious but what is the benefit of the optionalFrom functions instead of the built in try?, I realise that the optionalFrom methods essentially just do that.

Question: Convertible vs Mappable

The example in the README does not make this very clear. My first thought is that Convertible allows for inline value parsing with type completions from a JSON structure (hence accepting Any), whereas Mappable represents the logical JSON transformation to an entity in code, meaning a mappable type is just a bunch of convertibles. This lines up with what I see in DefaultConvertible.swift.

In the location example, why would you choose to make it Convertible instead of Mappable? They appear to be interchangeable in this case, but since location is a nested structure, rather than an inline value, my instinct would be to make it Mappable. Seems like I'm missing something here, thanks!

How to handle empty string to url transformations

Would love to hear what is a better approach in handling empty string to url transformations. Thanks.

    static func stringToURL(object: Any) throws -> URL {
        
        guard let string = object as? String else {
            throw MapperError.convertibleError(value: object, type: String.self)
        }
        
        // If string exists
        if string.isNotEmpty{
            return URL(string: string)!
        }else{
            return URL(string: "")! // ERRORS HERE BECAUSE STRING IS EMPTY AND IT IS TRYING TO UNWRAP THIS
        }
        
    }

Map root array into Models

Hi,
I need to parse root array of objects into Models. I have declared my model and was hoping to get it working like this
[Section].from(response) where response is array and excpted result should be array of Section not only Section itself. Please let me know how to do it in Mapper.

Thanks

Additional parameters when creating object with map.from("key")

Having a JSON:

{"name": "John"}

and a model:

struct User {
    let name: String
}

I implemented Mappable protocol in extension to User struct, so I can create my user models from JSON:

extension User: Mappable {
    init(map: Mapper) throws {
        name = try map.from("name")
    }
}

I would like to add additional property to User struct:

struct User {
    let name: String
    let age: Int
}

The value of that property doesn't come from JSON, I would like to provide it manually. Unfortunately, I can't add it to init(map: Mappable) initializator, as it will brake conformance to Mappable protocol.

Does mapper allows to add custom parameters to object when parsing JSONs?

I would like to be able to write code like this:

let map = Mapper(JSON: ...) // {"name": "John"}
let user: User = User(map: map, age: 33)

and:

let map = Mapper(JSON: ...) // {"user": {"name": "John"}}
let user: User = try map.from("user", age: 33)

which of course will require implementing custom from function for Mapper, but I am not sure how to do it or if it's even possible.

Handling of null values mapped to optional URL property

I'm mapping this JSON object:

{
      "id": 19627,
      "name": "Viktor Bestayev",
      "credits": "Cinematography",
      "image_url": null
}

to this model

struct Cast: Mappable {
    let castId: Int
    let name: String
    let credits: String
    let imageURL: URL?
    
    init(map: Mapper) throws {
        try castId = map.from("id")
        try name = map.from("name")
        try credits = map.from("credits")
        imageURL = map.optionalFrom("image_url")
    }
}

And this throws an MapperError.convertibleError because of the image_url null value. What is the intended way of handling this case?

Get feedback on failed parsing

I have a feature request, and I took a look at how to implement it and am struggling to find an idea:

  • I want to know when something goes wrong parsing, even if it was able to create a model (and I want the model also). Currently, if an optional field fails, it fails completely silently.

Ideas:

The easiest way to do it as far as I can see is add some sort of failure closure to the Mapper object which is called whenever a failure occurs.

A better way would be to throw an error, but include the actual model as part of that error. I don't think this is possible in swift though? Is it possible to include self in the object which you throw? Maybe you could do a convenience init which calls the other init first, then checks if there was an error, then throws a new error? Not sure if that works though...

Anyway, the real question is: is this a feature you think fits in with Mapper? It should definitely be opt in so backwards compatible, but interested in your thoughts.

error converting dictionary values

Great library!

I tried to convert a dictionary and got this error:

UpdateResponse error: TypeMismatchError("users", [greg: {
    name = greg;
}], Swift.Dictionary<Swift.String, Swift.Dictionary<Swift.String, FlexApp.User>>)

Here's some sample code to reproduce the error:

struct User: Mappable {
    let name:String

    init(map: Mapper) throws {
        try name = map.from("name")
    }
}

struct UserList: Mappable {
    let users:[String:[String:User]]

    init(map: Mapper) throws {
        do {
            try users = map.from("users")
        }
        catch let error {
            print("UpdateResponse error: \(error)")
            throw error
        }
    }
}

 let JSON = [
            "users": [
                "greg": [ "name" : "greg"]
            ]
        ]
let userList = UserList.from(JSON)
print("user list: ", userList)
let user = User.from(JSON["users"]!["greg"]!)
print("user: ", user)

using Mapper with Disk

Anyone tried using Mapper with Disk? https://github.com/saoudrizwan/Disk Basically the models should have Codable protocol for using Disk but whenever I add Codable beside Mappable I get an error "Type Model does not conform to protocol Decodable", "Type Model does not conform to protocol Encodable"

Mark App extension safe API only

It looks like this isn't using anything that's not extension safe, but it's not marked as safe. Could we get it marked as safe so I can get rid of this warning? :)

Add 'update' method

Is there any interest in adding an optional instance method to the Mappable protocol that allows a model to be updated post-creation. Similarly to the init(Mapper) initializer, this function would accept a mapper object, and give the model an opportunity to update any mutable properties. Happy to have a go at adding this...

Map Dictionary to [Self]?

I was discussing with @sberrevoets elsewhere, and other JSON libraries have functionality that allows you to return an array of Mappables, rather than just one.

I have a convert function, using a generic that takes vends a T, but I can’t make it take in [T], because [T] is not Mappable, even though T technically is. This would be useful because instead of having to create an intermediate object (like TList) around your Mappable type with one field ([T]), you'd be able to just vend a [T] from the JSON response.

Currently these two functions exist.

static func from(_ JSON: NSDictionary) -> Self?

static func from(_ JSON: NSArray) -> [Self]?

And I'd propose a third to one be added.

static func from(_ JSON: NSDictionary) -> [Self]?

Thanks a lot! Happy to add on any more information to help.

Carthage fails to build Mapper for watchOS

This line
carthage update --platform watchos
Gives such output:

*** Fetching mapper
*** Checking out mapper at "1.0.1"
*** xcodebuild output can be found in /var/folders/f_/t413twvd70969xm53wbmq4j00000gn/T/carthage-xcodebuild.beMwhr.log
*** Skipped building mapper due to the error:
Dependency "mapper" has no shared framework schemes for any of the platforms: watchOS

If you believe this to be an error, please file an issue with the maintainers at https://github.com/Lyft/mapper/issues/new

Adding --no-skip-current and/or removing --platform watchOS doesn't help

I'll try to check what's happening.

Get rid of `optionalFrom`

Working on another project, and I think this has been fixed in Swift 3 (however, it doesn't seem to work in playgrounds...only real projects).

As in, the compiler is smart enough to pick the right function based on return type now.

Idea: Typed transformations and conversions

Right now for transformations we do something like this:

func someTransform<T>(object: AnyObject?) -> T {
    return ...
}

I wonder if we could come up with an interface that changed our transforms to looking like this:

func someTransform<T, U: Convertible>(object: U) -> T {
    return ...
}

The benefit of this would be that right now for many transformations (and conversions), the first step is converting the AnyObject? to the actual JSON typed value. For example:

extension NSURL: Convertible {
   static func fromMap(value: AnyObject?) throws -> NSURL {
        if let string = value as? String, let URL = NSURL(string: string) {
            return URL
        }

        throw MapperError()
    }
}

The first step here is getting a string, and then using that to create a URL.

I think it could be nice for us to create an interface that allowed functions to have the more specialized type, and reduced some of the mapper duplication. Depending on how we did this, it could also serve for even more complex transformations:

func someTransform(objects: [Place]) -> [Place]) {
    return objects.map { $0.doSomething() }
}

Where right now this would be much more difficult.

I'd love to hear other's thoughts about this!

Array within array parsing

"exclusions" : [
[
{
"facility_id" : "1",
"options_id" : "4"
},
{
"facility_id" : "2",
"options_id" : "6"
}
],
[
{
"facility_id" : "1",
"options_id" : "3"
},
{
"facility_id" : "3",
"options_id" : "12"
}
],
[
{
"facility_id" : "2",
"options_id" : "7"
},
{
"facility_id" : "3",
"options_id" : "12"
}
]
]

Nested enum doesn't work

see below unit test used for the case.

 func testArrayOfEnum() {
        struct Test: Mappable {
            let nests: [Nested]
            init(map: Mapper) throws {
                try self.nests = map.from("nests")
            }
        }

        enum Nested:String {
            case SAMPLE1 = "SAMPLE1"
            case SAMPLE2 = "SAMPLE2"
        }

        let test = try! Test(map: Mapper(JSON: ["nests": ["SAMPLE1","SAMPLE2"]]))
        XCTAssertNil(test.nests)
    }

Add an optionalFrom to create optional array of RawRepresentables

#61 introduced a function to create an array of RawRepresentables.

However, we have a model that contains an optional array of enums, so optionalFrom would be needed. An implementation would be:

@warn_unused_result
public func optionalFrom<T: RawRepresentable where T.RawValue: Convertible,
    T.RawValue == T.RawValue.ConvertedType>(field: String, defaultValue: T? = nil) -> [T]?
{
    let value = try? self.JSONFromField(field)
    guard let array = value as? [AnyObject] else {
        return nil
    }

    let rawValues = try? array.map { try T.RawValue.fromMap($0) }
    return rawValues?.flatMap { T(rawValue: $0) ?? defaultValue }
}

If it's a welcome addition, I can make a PR adding it and some tests πŸš€

Offer subspec without default convertible implementations

Currently if consumers want to define their own Convertible implementations for the types we've deemed DefaultConvertible, such as String, or Int, there is no way for them to do this. I think a first easy step to improving this is by providing a subspec that can be used without including these default cases. The one downside is the cases that don't need to be overridden, consumers will have to re-add the empty protocol conformances.

This kinda fixes #114 and #98

Pod install unable to find specification

using pod 'ModelMapper', during pod install, the install fails with the following error:

[!] Unable to find a specification for 'ModelMapper'

I tried pod install, pod update, and a clean pod install and they all failed to find the spec

Converting JSON array that has multiple object types

Hi,

I have a JSON array that contains two types of objects (e.g. TypeA and TypeB), both of which correspond to Swift structs that conform to the same protocol 'CommonInfo'.
I know the type of each JSON object by a 'type' property on each object. How can I map this JSON array to a Swift array of type [CommonInfo] ?

Thanks!

DefaultConvertible causing issues for Doubles

The default implementation for double makes it impossible to allow automatic mapping from JSON that is represents floating point values a strings (which is common).

For example if I have:

{
   "radius" : 200,
   "latitude" : "34.0433903",
   "kind" : "circular",
   "longitude" : "-118.4542772"
}

I would like to map latitude like so (without having to remember to specify a custom transform each time).

let latitude = map.from("latitude")

Because DefaultConvertible extends Convertible I cannot extend Convertible to support this.
Any thoughts?

Suggestion for parsing one object from keyA or keyB?

I'm dealing with an API that pulls a Profile object from the key profile or profileSummary depending on it being a lite object or not but I always want the User object that owns the Profile to have a profile (it should not be optional). For now, I'm doing:

class User: Mappable {
    var _p1: Profile?
    var _p2: Profile?

    var profile: Profile {
        return self._p1 == nil ? self._p2! : self._p1!
    }

    required init(map: Mapper) throws {
        _p1 = map.optionalFrom("profileSummary")
        _p2 = map.optionalFrom("profile")
    }
}

is there a more idiomatic way?

Any way to know which key failed in JSON deserialization?

Hi there!

I am really loving Mapper, it allows the decoupled structure I've wanted from a JSON parser, but haven't been able to find elsewhere.

I've setup a relatively complicated set of models, where 1 model is dependent on 4 or 5 other models, and those models have their own dependencies inside as well. A simple version of these models may look something like this:

Feed (Consists of):
-- Header
---- title
---- subtitle
---- date

-- Footer
---- Image
------ URL
---- title
---- subtitle

When parsing the main model (Feed), at some point, one of those parsings fails (either in Header, Footer, or Image), and I'm having a difficult time figuring out which one is the one ultimately causing the JSON parsing to throw.

I've read through the readme a few times, read through the issues, and gone through the source code but still haven't been able to figure out if there's an easy way, other than commenting out all the models that don't work, and adding them back in one by one, to figure out which model is causing the parser to throw?

If there's any other information that may be helpful, please let me know. Thanks a lot!

Preliminary support for Swift 3

Would it be possible to maintain a swift 3.0 branch until the official release?

I just ran the Xcode 8 migrator over the codebase (and updated the project settings to enable the recommended whole module optimization as well while at it) and everything seems to build fine.
I'm just getting a lot of warn_unused_result warnings (not sure if already there previously) and an error on a missing file MapperTests. make test-iOS also fails on protocol 'Mappable' can only be used as a generic constraint because it has Self or associated type requirements and I didn't want to get much further into the code atm. Also didn't want to submit a PR with those issues^^

Warn for unused results

We should add @warn_unused_result to (probably) everything in Mapper. This might be obvious but it doesn't hurt!

Compile error for tvOS targets when using with carthage

When Mapper compiled with carthage 0.24 and linked into tvOS project in xcode 9b5 compiler says Module file was created for incompatible target x86_64-apple-ios8.0: I think this might be related with using single target for all platforms. Any solution?

Better support for deserializing to dictionaries

Hi! Mapper is mostly used for converting JSON to a single value or an array of values. The only dictionary deserialization function that I found was for the [Convertible: Convertible] case. I also saw a dictionary transformation available for converting an array of something to a dictionary.

There's plenty of other dictionary deserialization cases that we use heavily in our app, such as [Convertible: Mappable], [Convertible: [Mappable]], and even [Convertible: [Convertible]]. For example, [String: [String]] or [String: MyMappable].

I'm wondering if support for this type of deserialization is already in the works, or if it's something I should cook up myself and submit as a PR if you think it's a good idea. I was able to work around the [Convertible: Mappable] case with a transformation that looks like:

extension Transform {
    public static func toDictionary<Key, Value: Mappable>() -> (_ object: Any) throws -> [Key: Value]
        where Key: Hashable, Key: Convertible, Key.ConvertedType == Key
    {
        return { object in
            guard let objects = object as? [AnyHashable: [String: Any]] else {
                throw MapperError.convertibleError(value: object, type: [AnyHashable: [String: Any]].self)
            }

            var dictionary: [Key: Value] = [:]
            for (key, value) in objects {
                let convertedKey = try Key.fromMap(key)
                let model = try Value(map: Mapper(JSON: value as NSDictionary))
                dictionary[convertedKey] = model
            }

            return dictionary
        }
    }
}

However, it feels weird to do this as a transformation since this seems like a standard deserialization. It looks like I can't solve the array cases without modifying Mapper itself anyway which makes me think this should all live inside it.

As an aside, should Mapper work with extensions? I tried adding the dictionary functions via extension but several of the JSON helpers were not accessible, so I'll have to maintain a fork of this project in the meantime.

Realm with Mapper

Hi,
I am trying to use Mappable with Realms object. Previously, I had struct and it was subclassed from the Mappable and I implemented init function. For Realm, I converted my struct to class and conform Object protocol. Now issue is, our model contains optional Int? but in Realm Optional Int can be defined by 'RealmOptional; but when change type, I start getting errors in Mapper init function since that type is unknown to the compiler. Can you please send me any example how to use it with Mapper?

Thanks,
Amir

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.