Simple JSON Object mapping written in Swift

Related tags

JSON ObjectMapper
Overview

ObjectMapper

CocoaPods Carthage compatible Swift Package Manager Build Status

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

Features:

  • Mapping JSON to objects
  • Mapping objects to JSON
  • Nested Objects (stand alone, in arrays or in dictionaries)
  • Custom transformations during mapping
  • Struct support
  • Immutable support

The Basics

To support mapping, a class or struct just needs to implement the Mappable protocol which includes the following functions:

init?(map: Map)
mutating func mapping(map: Map)

ObjectMapper uses the <- operator to define how each member variable maps to and from JSON.

class User: Mappable {
    var username: String?
    var age: Int?
    var weight: Double!
    var array: [Any]?
    var dictionary: [String : Any] = [:]
    var bestFriend: User?                       // Nested User object
    var friends: [User]?                        // Array of Users
    var birthday: Date?

    required init?(map: Map) {

    }

    // Mappable
    func mapping(map: Map) {
        username    <- map["username"]
        age         <- map["age"]
        weight      <- map["weight"]
        array       <- map["arr"]
        dictionary  <- map["dict"]
        bestFriend  <- map["best_friend"]
        friends     <- map["friends"]
        birthday    <- (map["birthday"], DateTransform())
    }
}

struct Temperature: Mappable {
    var celsius: Double?
    var fahrenheit: Double?

    init?(map: Map) {

    }

    mutating func mapping(map: Map) {
        celsius 	<- map["celsius"]
        fahrenheit 	<- map["fahrenheit"]
    }
}

Once your class implements Mappable, ObjectMapper allows you to easily convert to and from JSON.

Convert a JSON string to a model object:

let user = User(JSONString: JSONString)

Convert a model object to a JSON string:

let JSONString = user.toJSONString(prettyPrint: true)

Alternatively, the Mapper.swift class can also be used to accomplish the above (it also provides extra functionality for other situations):

// Convert JSON String to Model
let user = Mapper<User>().map(JSONString: JSONString)
// Create JSON String from Model
let JSONString = Mapper().toJSONString(user, prettyPrint: true)

ObjectMapper can map classes composed of the following types:

  • Int
  • Bool
  • Double
  • Float
  • String
  • RawRepresentable (Enums)
  • Array<Any>
  • Dictionary<String, Any>
  • Object<T: Mappable>
  • Array<T: Mappable>
  • Array<Array<T: Mappable>>
  • Set<T: Mappable>
  • Dictionary<String, T: Mappable>
  • Dictionary<String, Array<T: Mappable>>
  • Optionals of all the above
  • Implicitly Unwrapped Optionals of the above

Mappable Protocol

mutating func mapping(map: Map)

This function is where all mapping definitions should go. When parsing JSON, this function is executed after successful object creation. When generating JSON, it is the only function that is called on the object.

init?(map: Map)

This failable initializer is used by ObjectMapper for object creation. It can be used by developers to validate JSON prior to object serialization. Returning nil within the function will prevent the mapping from occuring. You can inspect the JSON stored within the Map object to do your validation:

required init?(map: Map){
	// check if a required "name" property exists within the JSON.
	if map.JSON["name"] == nil {
		return nil
	}
}

StaticMappable Protocol

StaticMappable is an alternative to Mappable. It provides developers with a static function that is used by ObjectMapper for object initialization instead of init?(map: Map).

Note: StaticMappable, like Mappable, is a sub protocol of BaseMappable which is where the mapping(map: Map) function is defined.

static func objectForMapping(map: Map) -> BaseMappable?

ObjectMapper uses this function to get objects to use for mapping. Developers should return an instance of an object that conforms to BaseMappable in this function. This function can also be used to:

  • validate JSON prior to object serialization
  • provide an existing cached object to be used for mapping
  • return an object of another type (which also conforms to BaseMappable) to be used for mapping. For instance, you may inspect the JSON to infer the type of object that should be used for mapping (see examples in ClassClusterTests.swift)

If you need to implement ObjectMapper in an extension, you will need to adopt this protocol instead of Mappable.

ImmutableMappable Protocol

ImmutableMappable provides the ability to map immutable properties. This is how ImmutableMappable differs from Mappable:

ImmutableMappable Mappable
Properties
let id: Int
let name: String?
var id: Int!
var name: String?
JSON -> Model
init(map: Map) throws {
  id   = try map.value("id")
  name = try? map.value("name")
}
mutating func mapping(map: Map) {
  id   <- map["id"]
  name <- map["name"]
}
Model -> JSON
func mapping(map: Map) {
  id   >>> map["id"]
  name >>> map["name"]
}
mutating func mapping(map: Map) {
  id   <- map["id"]
  name <- map["name"]
}
Initializing
try User(JSONString: JSONString)
User(JSONString: JSONString)

init(map: Map) throws

This throwable initializer is used to map immutable properties from the given Map. Every immutable property should be initialized in this initializer.

This initializer throws an error when:

  • Map fails to get a value for the given key
  • Map fails to transform a value using Transform

ImmutableMappable uses Map.value(_:using:) method to get values from the Map. This method should be used with the try keyword as it is throwable. Optional properties can easily be handled using try?.

init(map: Map) throws {
    name      = try map.value("name") // throws an error when it fails
    createdAt = try map.value("createdAt", using: DateTransform()) // throws an error when it fails
    updatedAt = try? map.value("updatedAt", using: DateTransform()) // optional
    posts     = (try? map.value("posts")) ?? [] // optional + default value
    surname    = try? map.value("surname", default: "DefaultSurname") // optional + default value as an argument
}

mutating func mapping(map: Map)

This method is where the reverse transform is performed (model to JSON). Since immutable properties cannot be mapped with the <- operator, developers have to define the reverse transform using the >>> operator.

mutating func mapping(map: Map) {
    name      >>> map["name"]
    createdAt >>> (map["createdAt"], DateTransform())
    updatedAt >>> (map["updatedAt"], DateTransform())
    posts     >>> map["posts"]
}

Easy Mapping of Nested Objects

ObjectMapper supports dot notation within keys for easy mapping of nested objects. Given the following JSON String:

"distance" : {
     "text" : "102 ft",
     "value" : 31
}

You can access the nested objects as follows:

func mapping(map: Map) {
    distance <- map["distance.value"]
}

Nested keys also support accessing values from an array. Given a JSON response with an array of distances, the value could be accessed as follows:

distance <- map["distances.0.value"]

If you have a key that contains ., you can individually disable the above feature as follows:

func mapping(map: Map) {
    identifier <- map["app.identifier", nested: false]
}

When you have nested keys which contain ., you can pass the custom nested key delimiter as follows (#629):

func mapping(map: Map) {
    appName <- map["com.myapp.info->com.myapp.name", delimiter: "->"]
}

Custom Transforms

ObjectMapper also supports custom transforms that convert values during the mapping process. To use a transform, simply create a tuple with map["field_name"] and the transform of your choice on the right side of the <- operator:

birthday <- (map["birthday"], DateTransform())

The above transform will convert the JSON Int value to an Date when reading JSON and will convert the Date to an Int when converting objects to JSON.

You can easily create your own custom transforms by adopting and implementing the methods in the TransformType protocol:

public protocol TransformType {
    associatedtype Object
    associatedtype JSON

    func transformFromJSON(_ value: Any?) -> Object?
    func transformToJSON(_ value: Object?) -> JSON?
}

TransformOf

In a lot of situations you can use the built-in transform class TransformOf to quickly perform a desired transformation. TransformOf is initialized with two types and two closures. The types define what the transform is converting to and from and the closures perform the actual transformation.

For example, if you want to transform a JSON String value to an Int you could use TransformOf as follows:

let transform = TransformOf<Int, String>(fromJSON: { (value: String?) -> Int? in 
    // transform value from String? to Int?
    return Int(value!)
}, toJSON: { (value: Int?) -> String? in
    // transform value from Int? to String?
    if let value = value {
        return String(value)
    }
    return nil
})

id <- (map["id"], transform)

Here is a more condensed version of the above:

id <- (map["id"], TransformOf<Int, String>(fromJSON: { Int($0!) }, toJSON: { $0.map { String($0) } }))

Subclasses

Classes that implement the Mappable protocol can easily be subclassed. When subclassing mappable classes, follow the structure below:

class Base: Mappable {
    var base: String?
    
    required init?(map: Map) {

    }

    func mapping(map: Map) {
        base <- map["base"]
    }
}

class Subclass: Base {
    var sub: String?

    required init?(map: Map) {
        super.init(map)
    }

    override func mapping(map: Map) {
        super.mapping(map)
        
        sub <- map["sub"]
    }
}

Make sure your subclass implementation calls the right initializers and mapping functions to also apply the mappings from your superclass.

Generic Objects

ObjectMapper can handle classes with generic types as long as the generic type also conforms to Mappable. See the following example:

class Result<T: Mappable>: Mappable {
    var result: T?

    required init?(map: Map){

    }

    func mapping(map: Map) {
        result <- map["result"]
    }
}

let result = Mapper<Result<User>>().map(JSON)

Mapping Context

The Map object which is passed around during mapping, has an optional MapContext object that is available for developers to use if they need to pass information around during mapping.

To take advantage of this feature, simply create an object that implements MapContext (which is an empty protocol) and pass it into Mapper during initialization.

struct Context: MapContext {
	var importantMappingInfo = "Info that I need during mapping"
}

class User: Mappable {
	var name: String?
	
	required init?(map: Map){
	
	}
	
	func mapping(map: Map){
		if let context = map.context as? Context {
			// use context to make decisions about mapping
		}
	}
}

let context = Context()
let user = Mapper<User>(context: context).map(JSONString)

ObjectMapper + Alamofire

If you are using Alamofire for networking and you want to convert your responses to Swift objects, you can use AlamofireObjectMapper. It is a simple Alamofire extension that uses ObjectMapper to automatically map JSON response data to Swift objects.

ObjectMapper + Realm

ObjectMapper and Realm can be used together. Simply follow the class structure below and you will be able to use ObjectMapper to generate your Realm models:

class Model: Object, Mappable {
    dynamic var name = ""

    required convenience init?(map: Map) {
        self.init()
    }

    func mapping(map: Map) {
        name <- map["name"]
    }
}

If you want to serialize associated RealmObjects, you can use ObjectMapper+Realm. It is a simple Realm extension that serializes arbitrary JSON into Realm's List class.

To serialize Swift String, Int, Double and Bool arrays you can use ObjectMapperAdditions/Realm. It'll wrap Swift types into RealmValues that can be stored in Realm's List class.

Note: Generating a JSON string of a Realm Object using ObjectMappers' toJSON function only works within a Realm write transaction. This is because ObjectMapper uses the inout flag in its mapping functions (<-) which are used both for serializing and deserializing. Realm detects the flag and forces the toJSON function to be called within a write block even though the objects are not being modified.

Projects Using ObjectMapper

If you have a project that utilizes, extends or provides tooling for ObjectMapper, please submit a PR with a link to your project in this section of the README.

To Do

  • Improve error handling. Perhaps using throws
  • Class cluster documentation

Contributing

Contributions are very welcome 👍 😃 .

Before submitting any pull request, please ensure you have run the included tests and they have passed. If you are including new functionality, please write test cases for it as well.

Installation

Cocoapods

ObjectMapper can be added to your project using CocoaPods 0.36 or later by adding the following line to your Podfile:

pod 'ObjectMapper', '~> 3.5' (check releases to make sure this is the latest version)

Carthage

If you're using Carthage you can add a dependency on ObjectMapper by adding it to your Cartfile:

github "tristanhimmelman/ObjectMapper" ~> 3.5 (check releases to make sure this is the latest version)

Swift Package Manager

To add ObjectMapper to a Swift Package Manager based project, add:

.package(url: "https://github.com/tristanhimmelman/ObjectMapper.git", .upToNextMajor(from: "4.1.0")),

to your Package.swift files dependencies array.

Submodule

Otherwise, ObjectMapper can be added as a submodule:

  1. Add ObjectMapper as a submodule by opening the terminal, cd-ing into your top-level project directory, and entering the command git submodule add https://github.com/tristanhimmelman/ObjectMapper.git
  2. Open the ObjectMapper folder, and drag ObjectMapper.xcodeproj into the file navigator of your app project.
  3. In Xcode, navigate to the target configuration window by clicking on the blue project icon, and selecting the application target under the "Targets" heading in the sidebar.
  4. Ensure that the deployment target of ObjectMapper.framework matches that of the application target.
  5. In the tab bar at the top of that window, open the "Build Phases" panel.
  6. Expand the "Target Dependencies" group, and add ObjectMapper.framework.
  7. Click on the + button at the top left of the panel and select "New Copy Files Phase". Rename this new phase to "Copy Frameworks", set the "Destination" to "Frameworks", and add ObjectMapper.framework.
Comments
  • Issue with NSManagedObject class conforming to Mappable

    Issue with NSManagedObject class conforming to Mappable

    Hi,

    I'm trying to map directly JSON to a class model inheriting NSManagedObject. I created an extension that conform to Mappable and implement mapping.

    At compile time, I got a Swift compiler error, usr/bin/swiftc failed to exit code 1.

    It might be due to the init() method of the Mappable protocol. When reading the Mapper.swift class I found the following:

       /**
    * Maps a JSON dictionary to an existing object that conforms to Mappable.
    * Usefull for those pesky objects that have crappy designated initializers like NSManagedObject
    */
    public func map(JSON: [String : AnyObject], var toObject object: N) -> N {
        let map = Map(mappingType: .fromJSON, JSONDictionary: JSON)
        object.mapping(map)
        return object
    }
    

    which would be the function to use in order to set properties of the entity once created.

    Could you post an example of an NSManagedObject class conforming to Mappable?

    Thanks

    opened by hopiaw 42
  • Mapping dictionary with no name on key?

    Mapping dictionary with no name on key?

    Hi there,

    I'm facing a problem, which I can't seem to figure out. I have a JSON dictionary similar to this:

    {"3371": [{"id":11,"sId":2,"dateTime":"2016-10-05T04:00:00.000Z"},
    {"id":12,"sId":3,"dateTime":"2016-10-05T04:00:00.000Z"}]},
    {"3728": [{"id":3,"sId":2,"dateTime":"2016-10-05T04:00:00.000Z"},
    {"id":12,"sId":3,"dateTime":"2016-10-05T04:00:00.000Z"}]}
    

    So a dictionary containing an arrays. The problem seems to be, the key has no name, so I can't figure out how to map it?

    opened by Dbigshooter 39
  • Subclassing and Realm

    Subclassing and Realm

    I have this class

    import ObjectMapper
    import RealmSwift
    
    class Base: Object, Mappable {
        dynamic var id: String?
        dynamic var objectType: String?
        dynamic var createdAt: String? // TODO: make sure this gets converted to an NSDate!
    
        required convenience init?(_ map: Map) {
            self.init()
        }
    
        func mapping(map: Map) {
            id <- map["id"]
            createdAt <- map["created_at"]
            objectType <- map["_class"]
        }
    }
    

    and then I subclass it here:

    import ObjectMapper
    import RealmSwift
    
    class User: Base {
        dynamic var username: String?
        dynamic var bio: String?
    
        override func mapping(map: Map) {
            super.mapping(map)
            username <- map["username"]
            bio <- map["bio"]
        }
    }
    

    And it won't build. Some reason, I'm getting this error: <unknown>:0: error: must call a designated initializer of the superclass 'Base'

    worries me >_<

    Is there something I'm missing??

    opened by jpmcglone 32
  • Decreased performance on large JSON object in Swift 2.0

    Decreased performance on large JSON object in Swift 2.0

    The app that I'm working on consumes very large (~1 MB) JSON objects. In Swift 1.2, ObjectMapper was able to map it in < 5s. In Swift 2.0, it is taking > 50s.

    This occurs in older versions of ObjectMapper and the latest. The difference seems to be Swift 1.2 versus Swift 2.0.

    opened by WarDrummer 28
  • Swift 5 and try?

    Swift 5 and try?

    Parsing complicated object with optional objects as a parameter does not work.

    public struct Push: ImmutableMappable {
      public let contact: MeetingContactPush?
    
      public init(map: Map) throws {
        contact = try? map.value("Contact")
      }
    
    }
    
    public struct MeetingContactPush: ImmutableMappable {
    
      public let userId: Int
      public let phone: String
      public let name: String?
    
      public init(map: Map) throws {
        userId = try map.value("Id")
        phone = try map.value("Phone")
        name = try? map.value("Name")
      }
    
    }
    
    

    Contact will be always nil

    opened by YevhenHerasymenko 25
  • Realm.io List type

    Realm.io List type

    Superb library! It helped me so much til now! The only problem I have right now is mapping List to my model. Basically it is used in Realm to define to-many relationship to a foreign model.

    In my JSON a single object looks like this

    "arretsPhysiques": [
        {
            "codeArret": "31DC",
            "coordonnees": {
                "altitude": 0,
                "latitude": 46.20166851756986,
                "longitude": 6.161853747996533
            },
            "ligneDestinations": {
                "ligneDestination": [
                    {
                        "destination": "Jar.-Botanique",
                        "destinationMajuscule": "JAR. BOTANIQUE",
                        "ligne": 1
                    },
                    {
                        "destination": "Gare Cornavin",
                        "destinationMajuscule": "GARE CORNAVIN",
                        "ligne": 9
                    }
                ]
            },
            "mnemol": "31DC00",
            "nomArret": "31-déc"
        }
        ...
    ]
    

    And model like so:

    class Stop: Object, Mappable {
    
        dynamic var physicalStopCode = ""
        dynamic var stopCode = ""
        dynamic var stopName = ""
        dynamic var coordinates = Coordinates()
        dynamic var connections = List<Connection>()
        dynamic var distance: Double = 0.0
        override class func primaryKey() -> String? {
            return "physicalStopCode"
        }
    
        override static func ignoredProperties() -> [String] {
            return ["distance"]
        }
    
        required convenience init?(_ map: Map) {
            self.init()
            mapping(map)
        }
    
        func mapping(map: Map) {
            physicalStopCode <- map["codeArret"]
            stopCode <- map["mnemol"]
            stopName <- map["nomArret"]
            coordinates <- map["coordonnees"]
            connections <- map["ligneDestinations"]
        }
    }
    

    I'm able to map every single property but ligneDestination which is strangely nested inside ligneDestinations

    Mapped object returns empty List<Connection> . I also tried connections <- map["ligneDestinations.ligneDestination"] to get this nested array of object but with no luck.

    So does ObjectMapper supports List type? Or any suggestions? Thanks! :)

    opened by staticdreams 23
  • Swift 3 - Float mapping issue

    Swift 3 - Float mapping issue

    Since swift 3, ObjectMapper seems to not map float type correctly anymore

    For example I have this dictionnary : let dict: [String:Any] = ["manager":1, "self_assessment":0, "average":0, "total_answers":1]

    and this object :

    class AnswerOverview: Object, Mappable {
        dynamic var manager: Float = 0
        dynamic var selfAssessment: Float = 0
        dynamic var average: Float = 0
        dynamic var totalAnswers: Int = 0
    }
    

    when i tried to map it : let answerOverview = Mapper<AnswerOverview>().map(JSON: dict)

    my float values are still empty ( all equal to 0)

    I have unit test for this and it was passing before with swift 2.2

    opened by Sianay 22
  • No operator overload for `<-` where T is mappable

    No operator overload for `<-` where T is mappable

    This is useful in cases where the object relationship is not inline. This can happen for a number of reasons, we use it in cases where an object may show up in the response many times so we use a URI to reference that object and create a placeholder in our datastore. When we encounter the full payload we then update our placeholder. Similar behaviour can be seen with links in JSON API

    Id be happy to add this if you think its reasonable.

    opened by tapi 22
  • Incorrect mapping Object-> Json when is an array of objects which implements the Mapping protocol

    Incorrect mapping Object-> Json when is an array of objects which implements the Mapping protocol

    I don't understand why if i have a transform of NSURL i have to make a custom transform of NSURL to send an array of NSURL, since when i map JSON->Object i get a correct mapping, but when i send the objects OBJECT-JSON seems the mapping is incorrect. For example, i have an array of Address that i get from the server, i implemeted the protocol Mapping in the class Address, and everything is ok, i get 'N' addresses mapped, but when i send it back as an array of Address, the mapping is incorrect. What im missing?

    opened by ivangodfather 21
  • After updating to Xcode 9.3 and Swift 4.1 Float is not able to map the values

    After updating to Xcode 9.3 and Swift 4.1 Float is not able to map the values

    I just updated to Xcode 9.3 and Swift 4.1 and Float is not able to map the values, but when I changed Float to CGFloat it is working fine.

    It is giving lots of compilation warnings also. PFA attached screenshot of warnings.

    screen shot 2018-03-31 at 12 53 09 pm
    opened by krishnameena 20
  • [Immutable] Make init throw + Transform & Mappable support

    [Immutable] Make init throw + Transform & Mappable support

    @tristanhimmelman

    Related to https://github.com/Hearst-DD/ObjectMapper/issues/383

    This PR adds various improvements over the current immutable mapping support (see commented section in https://raw.githubusercontent.com/Hearst-DD/ObjectMapper/master/README.md)

    Summary of changes

    Immutable mapping

    Immutable mapping can now be written like this:

    class Base: Mappable {
        let base: String
        let date: NSDate
    
        init(_ map: Map) throws {
            base = try map["base"].valueOrFail()
            date = try map["date].valueWithTransformOrFail(DateTransform())
            // And a lot more
        }
    
        mutating func mapping(map: Map) {
            // unchanged
        }
    }
    

    This required the following change in the Mappable protocol:

    public protocol Mappable {
    --  init?(_ map: Map)
    ++   init(_ map: Map) throws
    

    This has a couple advantages:

    • There's no more need to call map.isValid at the end of the initializer.
    • You can exit the initializer early if one of the mappings failed.
    • You can add custom validation logic and throw an error if the mapping doesn't fit your needs.
    • The library can be extended to throw meaningful errors (like couldn't map attribute "base" with type "Base", payload: "123"). As of now it just throws a very basic ErrorType subclass (MappingError)

    Transforms & Mappable

    Added support for the following immutable mapping types. valueOrFail() throws, value() returns an optional.

    • Basic type T, with T, [T], [String: T]
    • Transforms mapping via valueWithTransform/valueWithTransformOrFail. T, [T], [String: T]
    • Mappable mapping, with T, [T], [String: T].

    ImmutableObjectTests

    Moved the small Immutable test from ObjectMapperTests to ImmutableObjectTests and added all cases that were covered in this PR. We might want to break it down into multiple tests, but I went for simplicity for this first draft.

    Discussion

    @tristanhimmelman This PR's main goal is to kick off a conversation about immutable mapping. While I think the interface is acceptable, it's more meant to be a starting point to discuss how the library could be modified to support such a feature.

    I'd love your input on the following points:

    • What do you think about the init change? Do you think it's acceptable to break the interface for such a feature?
    • How about mapping()? Right now it's really awkward to have to switch on the mapping type, create variables and map them with an inout operator. I was thinking about the following:
      • Only allow JSON => object mapping via init(map: Mapping) and drop the <- operator
      • Add a -> operator in mapping(map: Mapping) and rename that method to serialize().

    Also, if you'd rather go with another process to discuss immutability changes, just let me know! Thank you :)

    opened by ldiqual 20
  • Support Multi-Keys

    Support Multi-Keys

    Different JSON use different keys to identify the values that mean same thing. Likes, First JSON:

    {
        "code" : 200,
        "message" : "success"
    }
    

    Second JSON:

    {
        "code" : 200,
        "msg" : "success"
    }
    

    For the 'success' value, you can access the multi-keys object as follows:

    func mapping(map: Map) {
        identifier <- map["message|msg", nested: false, delimiter: "|"]
    }
    
    opened by tospery 0
  • Map.subscript(key:nested:delimiter:ignoreNil:). crash

    Map.subscript(key:nested:delimiter:ignoreNil:). crash

    it is Crash log

    Incident Identifier: 5B9B24FD-FE3F-426C-B245-344F3FABAF12 Hardware Model: iPhone12,5 Process: Xxxxx [1426] Path: /private/var/containers/Bundle/Application/12DF6929-8420-4B09-B5D5-144FC3D27F24/Xxxxx.app/Xxxxx Identifier: XXXX Version: 4.6.0 (3691) AppStoreTools: 13F15 AppVariant: 1:iPhone12,5:15 Code Type: ARM-64 (Native) Role: Non UI Parent Process: launchd [1] Coalition: XXXXX [747]

    Date/Time: 2022-05-23 07:03:55.2024 +0530 Launch Time: 2022-05-23 07:03:08.4966 +0530 OS Version: iPhone OS 15.3.1 (19D52) Release Type: User Baseband Version: 3.01.02 Report Version: 104

    Exception Type: EXC_CRASH (SIGKILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Termination Reason: FRONTBOARD 2343432205 <RBSTerminateContext| domain:10 code:0x8BADF00D explanation:scene-create watchdog transgression: application:1426 exhausted CPU time allowance of 3.81 seconds ProcessVisibility: Background ProcessState: Running WatchdogEvent: scene-create WatchdogVisibility: Background WatchdogCPUStatistics: ( "Elapsed total CPU time (seconds): 7.850 (user 7.850, system 0.000), 54% CPU", "Elapsed application CPU time (seconds): 4.513, 31% CPU" ) reportType:CrashLog maxTerminationResistance:Interactive>

    Triggered by Thread: 0

    Kernel Triage: VM - Compressor failed a blocking pager_get VM - Compressor failed a blocking pager_get VM - Compressor failed a blocking pager_get VM - Compressor failed a blocking pager_get VM - Compressor failed a blocking pager_get

    Thread 0 name: Thread 0 Crashed: 0 libswiftCore.dylib 0x0000000185f7d0f8 swift_conformsToProtocolMaybeInstantiateSuperclasses(swift::TargetMetadataswift::InProcess const*, swift::TargetProtocolDescriptorswift::InProcess const*, bool) + 1260 (atomic:0) 1 libswiftCore.dylib 0x0000000185f7cd2c swift_conformsToProtocolMaybeInstantiateSuperclasses(swift::TargetMetadataswift::InProcess const*, swift::TargetProtocolDescriptorswift::InProcess const*, bool) + 288 (ProtocolConformance.cpp:236) 2 libswiftCore.dylib 0x0000000185f7c8a0 swift_conformsToProtocol + 136 (ProtocolConformance.cpp:1000) 3 libswiftCore.dylib 0x0000000185f40784 tryCast(swift::OpaqueValue*, swift::TargetMetadataswift::InProcess const*, swift::OpaqueValue*, swift::TargetMetadataswift::InProcess const*, swift::TargetMetadataswift::InProcess const*&, sw... + 2244 (DynamicCast.cpp:2233) 4 libswiftCore.dylib 0x0000000185f404dc tryCast(swift::OpaqueValue*, swift::TargetMetadataswift::InProcess const*, swift::OpaqueValue*, swift::TargetMetadataswift::InProcess const*, swift::TargetMetadataswift::InProcess const*&, sw... + 1564 (DynamicCast.cpp:0) 5 libswiftCore.dylib 0x0000000185f3fdb4 swift_dynamicCastImpl(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetMetadataswift::InProcess const*, swift::TargetMetadataswift::InProcess const*, swift::DynamicCastFlags) + 72 (DynamicCast.cpp:2305) 6 Xxxxx 0x0000000108027180 specialized Map.subscript(key:nested:delimiter:ignoreNil:) + 692 (Map.swift:110) 7 Xxxxx 0x00000001080258f4 $s12ObjectMapper3MapC9subscript33_B5D1A970400C81B87B0A9E4C4DDAEFE4LL3key6nested9delimiter9ignoreNilACSS_SbSgSSSbtF + 20 (:0) 8 Xxxxx 0x00000001080258f4 Map.subscript.getter + 28 (Map.swift:65) 9 Xxxxx 0x000000010683e2d0 0x1045c8000 + 36135632 10 Xxxxx 0x000000010683df90 0x1045c8000 + 36134800 11 Xxxxx 0x000000010683e71c 0x1045c8000 + 36136732 12 Xxxxx 0x0000000108029f48 Mapper.map(JSON:) + 644 (Mapper.swift:105) 13 Xxxxx 0x000000010802d4ec $sSDySSypGxSgs5Error_pIggrzo_AaBsAC_pIegnrzo_12ObjectMapper12BaseMappableRzlTR + 8 (:0) 14 Xxxxx 0x000000010802d4ec partial apply for thunk for @callee_guaranteed (@guaranteed [String : Any]) -> (@out A?, @error @owned Error) + 24 15 Xxxxx 0x000000010802db10 thunk for @callee_guaranteed (@guaranteed [String : Any]) -> (@out A?, @error @owned Error)partial apply + 12 16 Xxxxx 0x0000000108029ac4 Dictionary.filterMap(:) + 1936 (Mapper.swift:486) 17 Xxxxx 0x000000010802b360 Mapper.mapDictionary(JSON:) + 132 (Mapper.swift:193) 18 Xxxxx 0x0000000108029028 Mapper.mapDictionary(JSONObject:) + 108 19 Xxxxx 0x000000010801eeac static FromJSON.optionalObjectDictionary(:map:) + 408 (FromJSON.swift:147) 20 Xxxxx 0x000000010802e3fc <- infix(::) + 168 21 Xxxxx 0x000000010683e870 0x1045c8000 + 36137072 22 Xxxxx 0x000000010683e7b8 0x1045c8000 + 36136888 23 Xxxxx 0x000000010683ea4c 0x1045c8000 + 36137548 24 Xxxxx 0x0000000108029f48 Mapper.map(JSON:) + 644 (Mapper.swift:105) 25 Xxxxx 0x0000000108028c0c Mapper.map(JSONObject:) + 116 (Mapper.swift:89) 26 Xxxxx 0x0000000105b72e34 0x1045c8000 + 22720052 27 Xxxxx 0x0000000107b99268 specialized closure #2 in closure #2 in static XxxxxNetwork.request(:callbackQueue:thisProvider:success:error:failure:) + 368 28 Xxxxx 0x0000000107b99a98 partial apply for specialized closure #3 in closure #2 in static XxxxxNetwork.request(:callbackQueue:thisProvider:success:error:failure:) + 72 29 Xxxxx 0x000000010497d3f4 0x1045c8000 + 3888116 30 libdispatch.dylib 0x0000000180e79924 _dispatch_call_block_and_release + 32 (init.c:1517) 31 libdispatch.dylib 0x0000000180e7b670 _dispatch_client_callout + 20 (object.m:560) 32 libdispatch.dylib 0x0000000180e89b70 _dispatch_main_queue_callback_4CF + 944 (inline_internal.h:2601) 33 CoreFoundation 0x00000001811c1d84 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 16 (CFRunLoop.c:1795) 34 CoreFoundation 0x000000018117bf5c __CFRunLoopRun + 2540 (CFRunLoop.c:3144) 35 CoreFoundation 0x000000018118f468 CFRunLoopRunSpecific + 600 (CFRunLoop.c:3268) 36 GraphicsServices 0x000000019cd3338c GSEventRunModal + 164 (GSEvent.c:2200) 37 UIKitCore 0x0000000183b325d0 -[UIApplication _run] + 1100 (UIApplication.m:3493) 38 UIKitCore 0x00000001838b0f74 UIApplicationMain + 364 (UIApplication.m:5047) 39 Xxxxx 0x00000001047ccd50 0x1045c8000 + 2116944 40 dyld 0x000000010b8d9aa4 start + 520 (dyldMain.cpp:879)

    opened by 405092901 0
  • Undefined vs. nil

    Undefined vs. nil

    When I write to JSON, I'd sometimes like to write:

    "test": null

    But other times just omit "test".

    I made a simple struct that has undefined, null, or defined(Value) -- but I cannot for the life of me figure out how to make it generate some keys with "null" and omit others.

    opened by jpmcglone 1
  • hope support the

    hope support the "|" separator

    like, mutating func mapping(map: Map) { id <- map["areaId|serverId"] } when has not areaId, use serverId. can modify the follow code to support. private func subscript(key: String, nested: Bool? = nil, delimiter: String = ".", ignoreNil: Bool = false) -> Map { // save key and value associated to it currentKey = key keyIsNested = nested ?? key.contains(delimiter) nestedKeyDelimiter = delimiter

    	if mappingType == .fromJSON {
    		// check if a value exists for the current key
    		// do this pre-check for performance reasons
    		if keyIsNested {
    			// break down the components of the key that are separated by delimiter
    			(isKeyPresent, currentValue) = valueFor(ArraySlice(key.components(separatedBy: delimiter)), dictionary: JSON)
    		} else {
    			var object = JSON[key]
    

    // add this code if object == nil && key.contains(delimiter) { let components = key.components(separatedBy: delimiter) for item in components { object = JSON[item] if object != nil { break } } } // end add

                var isNSNull = object is NSNull
    			isKeyPresent = isNSNull ? true : object != nil
    			currentValue = isNSNull ? nil : object
    		}
    		
    		// update isKeyPresent if ignoreNil is true
    		if ignoreNil && currentValue == nil {
    			isKeyPresent = false
    		}
    	}
    	
    	return self
    }
    
    opened by tospery 0
  • Module compiled with Swift 5.2.4 cannot be imported by the Swift 5.5.1 compiler, Xcode 13.1 Error

    Module compiled with Swift 5.2.4 cannot be imported by the Swift 5.5.1 compiler, Xcode 13.1 Error

    So basically I faced this error on Xcode 13.1 and tried building the 3.5 to 4.2 version but did not get built.

    Module compiled with Swift 5.2.4 cannot be imported by the Swift 5.5.1 compiler: /Users/Documents/Workspace/Project/Carthage/Build/iOS/ObjectMapper.framework/Modules/ObjectMapper.swiftmodule/x86_64-apple-ios-simulator.swiftmodule

    Screenshot 2021-12-21 at 3 22 18 PM

    Currently same error with

    github "Hearst-DD/ObjectMapper" "3.5.3" to github "Hearst-DD/ObjectMapper" "4.2.0" System: macOSBigSur: 11.6 (20G165)

    Could anyone please help me on this?

    I tried a couple of StackOverflow answers but does not seem to be working. Tried with NEW BUILD SYSTEM vs LEGACY BUILD SYSTEM.

    and some options in build settings.

    opened by sanojKashyap 0
  • Object converting to JSON is not working properly (Object.toJSON() or Object.toJSONString(prettyPrint: true))

    Object converting to JSON is not working properly (Object.toJSON() or Object.toJSONString(prettyPrint: true))

    Hello,

    Greetings of the day!

    First of all thanks for this wonderful library, I like it. 🙂

    I just want to write an issue which I am facing, I work as an iOS developer and this issue occurs with Xcode-swift.

    I am trying to upload media in bytes to API, let me explain it step by step:-

    1. Created blank mappable object for e.g. let object = WorkOrderRequest(JSON: [:])
    2. Added data to object for e.g. object.subJobID = 2 and other data accordingly.

    Example:- let attachment: WorkOrderAttachments? attachment.MimeType = "ApplicationPDF" attachment.FileName = "Name" attachment.Media = Image object in bytes(Data)

    assign that to 'object.WorkOrderAttachments = [attachment]'

    Until here everything works fine, even I can extract each specific object(Media object as well).

    1. Now when I try to upload it to API, I have to convert the object to JSON and pass it to the API. but somehow converting gets failed. I can see all the other objects in JSON except 'Media' somehow it gets lost or not converted.

    Your help is much appreciated. Looking forward to hearing from you guys soon. TIA

    Your JSON dictionary:

    [ "SubJobID": 2, "WorkOrderAttachments": [ { "MimeType": MimeType.ApplicationPDF, "FileName": "WorkAuthorizationEmergency_08252021_1.pdf", "Media": 3028bytes } ], "WoStatus": 1 ]

    Your model:

    class NewWorkOrderRequest: NSObject, Mappable { var subJobID : Int64? var woStatus : Int64? var workOrderAttachments : [WorkOrderAttachments]?

    required init? (map: Map) {
    }
    
    func mapping(map: Map) {
        subJobID <- map["SubJobID"]
        woStatus <- map["WoStatus"]
        workOrderAttachments <- map["WorkOrderAttachments"]
    }
    

    }

    class WorkOrderAttachments: NSObject, Mappable {

    var media : Data?
    var fileName : String?
    var mimeType : MimeType?
    
    required init? (map: Map) {
    }
    
    func mapping(map: Map) {
        media <- map["Media"]
        mimeType <- map["MimeType"]
        fileName <- map["FileName"]
    }
    

    }

    What you did:

    Data imported to object correctly, but while converting it to JSON, 'Media' object gets null and not passed to API.

    For e.g.:- 'Object.toJSON()'

    after converting, the result is like:-

    [ "WoStatus": 1, "SubJobID": 2, "WorkOrderAttachments": [ { "MimeType": "application/pdf", "FileName": "WorkAuthorizationEmergency_08252021_1.pdf" } ] ]

    What you expected:

    I expected something like:

    Convert from Mappable object to JSON or JSONString is not working properly and data of object gets lost.

    opened by smeet-chavda 0
Releases(4.2.0)
  • 4.2.0(May 18, 2020)

  • 4.1.0(May 17, 2020)

  • 4.0.0(May 17, 2020)

  • 3.5.3(May 17, 2020)

  • 3.5.2(Mar 16, 2020)

  • 3.5.1(Jun 25, 2019)

  • 3.5.0(Jun 6, 2019)

  • 2.2.8(Jul 11, 2017)

  • 2.2.7(May 26, 2017)

  • 2.2.6(Apr 20, 2017)

    • Increase decimal transform precision in NSDecimalTransform
    • Support for ImmutableMappable as property of Mappable
    • Allow URLTransform to accept custom character set
    Source code(tar.gz)
    Source code(zip)
  • 2.2.5(Feb 28, 2017)

  • 2.2.4(Feb 25, 2017)

    • Support for UnsignedInteger/SignedInteger (Thanks @devxoul)
    • Support for ImmutableMappable 2 dimensional arrays (Thanks @afonsograca)
    • Linux bug fixes (Thanks @foldericon)
    Source code(tar.gz)
    Source code(zip)
  • 2.2.3(Feb 15, 2017)

  • 2.2.2(Dec 11, 2016)

    Support for printing null values in ToJSON. See shouldIncludeNilValues variable in Mapper. Thanks @traylewin
    Bug fix: MapContext is now being correctly passed down when mapping nested objects (for ImmutableMappable mappings) Thanks @haritowa

    Source code(tar.gz)
    Source code(zip)
  • 2.2.1(Nov 2, 2016)

  • 2.2.0(Oct 23, 2016)

    • Improved support for ImmutableMapable (Thanks @devxoul)
    • New HexColorTransform (Thanks @vitkuzmenko)
    • Support for a custom nested key delimiter (Thanks @devxoul)
    • Support for Swift Package Manager (Thanks @diogoguimaraes)
    Source code(tar.gz)
    Source code(zip)
  • 2.1.0(Oct 7, 2016)

    • Support of Immutable mappings. Thanks to @devxoul!
      • New protocol ImmutableMappable which defines a throwing init function where immutable mappings can be performed
      • New operator for Model to JSON generation >>>
    • Bug fix: DateTransforms now marked as open
    • Map.currentKey is now public
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Sep 14, 2016)

    • Support for Swift 3
    • The Mappable extension now supports the MapContext
    • Updates to Mapper to make function definitions require named parameters
    Source code(tar.gz)
    Source code(zip)
  • 1.5.0(Sep 7, 2016)

    • ObjectMapper can now be implemented within an extension using the StaticMappable protocol. (Thanks @andrebraga)

    Below is the new protocol structure

    /// BaseMappable should not be implemented directly. Mappable or StaticMappable should be used instead
    public protocol BaseMappable {
        /// This function is where all variable mappings should occur. It is executed by Mapper during the mapping (serialization and deserialization) process.
        mutating func mapping(map: Map)
    }
    public protocol Mappable: BaseMappable {
        /// This function can be used to validate JSON prior to mapping. Return nil to cancel mapping at this point
        init?(_ map: Map)
    }
    public protocol StaticMappable: BaseMappable {
        /// This function should return an instance of BaseMappable that ObjectMapper will use for mapping. It can also be used to:
        ///     1) provide an existing cached object to be used for mapping
        ///     2) return an object of another class (which conforms to Mappable) to be used for mapping. For instance, you may inspect the JSON to infer the type of object that should be used for any given mapping
        ///     3) perform validation prior to mapping
        static func objectForMapping(map: Map) -> BaseMappable?
    }
    
    • Compilation speed improvements (@ivanbruel)
    • NSDataTransform
    Source code(tar.gz)
    Source code(zip)
  • 1.4.0(Aug 6, 2016)

  • 1.3.0(May 12, 2016)

    • Removed the MappableCluster protocol by adding the objectForMapping function into Mappable and adding a default implementation in an extension making it an optional function
    • Created MapContext protocol which can be implemented by developers and used to pass information around during mapping. Pass the MapContext object into Mapper in init and the context will be available in the Map object (map.context) during mapping.
    • Added NSDecimalNumberTransform
    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(Mar 25, 2016)

    • Updates to support Swift 2.2 changes
    • JSON containing nil objects is no longer ignored. This is especially important when mapping to an existing object where the developer may want to remove a variable based on a nil JSON object.
    Source code(tar.gz)
    Source code(zip)
Owner
Tristan Himmelman
Tristan Himmelman
Decodable Simple and strict, yet powerful object mapping made possible by Swift 2's error handling.

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

Johannes Lund 1k Jul 15, 2022
Easy JSON to NSObject mapping using Cocoa's key value coding (KVC)

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

Mobile Jazz 249 Jun 29, 2022
JSON object with Swift

JSON JSON using @dynamicMemberLookup, which allows us to write more natural code

Jewelz Hu 0 Dec 17, 2021
JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift.

JSEN /ˈdʒeɪsən/ JAY-sən JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift. A JSON, as defined in the EC

Roger Oba 8 Nov 22, 2022
Swift-json - High-performance json parsing in swift

json 0.1.4 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
JSON-Practice - JSON Practice With Swift

JSON Practice Vista creada con: Programmatic + AutoLayout Breve explicación de l

Vanesa Giselle Korbenfeld 0 Oct 29, 2021
Ss-json - High-performance json parsing in swift

json 0.1.1 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON.

JSONFeed Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON. For more information about this new feed format visit: https:/

Toto Tvalavadze 31 Nov 22, 2021
JSONNeverDie - Auto reflection tool from JSON to Model, user friendly JSON encoder / decoder, aims to never die

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

John Lui 454 Oct 30, 2022
Property mapping for Objective-C iOS apps.

Stop repeating your data parsing code in iOS apps. Data parsing is one of most common tasks we need to do in our apps, yet still majority of people do

Krzysztof Zabłocki 1.1k Sep 8, 2022
An extremely simple JSON helper written in Swift.

Alexander Alexander is an extremely simple JSON helper written in Swift. It brings type safety and Foundation helpers to the cumbersome task of JSON u

HODINKEE 36 Sep 15, 2022
A library to turn dictionary into object and vice versa for iOS. Designed for speed!

WAMapping Developed and Maintained by ipodishima Founder & CTO at Wasappli Inc. Sponsored by Wisembly A fast mapper from JSON to NSObject Fast Simple

null 8 Nov 20, 2022
Dogtector: dog breed detection app for iOS using YOLOv5 model combined with Metal based object decoder optimized

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

Bartłomiej Pluta 21 Aug 1, 2022
HandyJSON is a framework written in Swift which to make converting model objects to and from JSON easy on iOS.

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

Alibaba 4.1k Dec 29, 2022
Himotoki (紐解き) is a type-safe JSON decoding library written purely in Swift.

Himotoki Himotoki (紐解き) is a type-safe JSON decoding library written purely in Swift. This library is highly inspired by the popular Swift JSON parsin

IKEDA Sho 799 Dec 6, 2022
JASON is a faster JSON deserializer written in Swift.

JASON is a faster JSON deserializer written in Swift. JASON is the best framework we found to manage JSON at Swapcard. This is by far the fastest and

Damien 1k Oct 15, 2022
ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects to and from JSON.

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

Tristan Himmelman 9k Jan 2, 2023
A type-safe JSON-RPC 2.0 library purely written in Swift

JSONRPCKit JSONRPCKit is a type-safe JSON-RPC 2.0 library purely written in Swift. // Generating request JSON let batchFactory = BatchFactory(version:

Shinichiro Oba 178 Mar 18, 2022
An iOS framework for creating JSON-based models. Written in Swift.

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

Oven Bits 448 Nov 8, 2022