diff --git a/ObjectMapper.xcodeproj/project.pbxproj b/ObjectMapper.xcodeproj/project.pbxproj index b1ed26b3..1c6a5aac 100644 --- a/ObjectMapper.xcodeproj/project.pbxproj +++ b/ObjectMapper.xcodeproj/project.pbxproj @@ -36,6 +36,9 @@ 6A412A181BAC830B001C3F67 /* ClassClusterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A412A161BAC770C001C3F67 /* ClassClusterTests.swift */; }; 6A412A241BB0DA26001C3F67 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A412A231BB0DA26001C3F67 /* PerformanceTests.swift */; }; 6A412A251BB0DA26001C3F67 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A412A231BB0DA26001C3F67 /* PerformanceTests.swift */; }; + 6A442CA11CE251F100AB4F1F /* MapContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A442CA01CE251F100AB4F1F /* MapContextTests.swift */; }; + 6A442CA21CE251F100AB4F1F /* MapContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A442CA01CE251F100AB4F1F /* MapContextTests.swift */; }; + 6A442CA31CE251F100AB4F1F /* MapContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A442CA01CE251F100AB4F1F /* MapContextTests.swift */; }; 6A51372C1AADDE2700B82516 /* DateFormatterTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51372B1AADDE2700B82516 /* DateFormatterTransform.swift */; }; 6A51372F1AADE12C00B82516 /* CustomTransformTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51372E1AADE12C00B82516 /* CustomTransformTests.swift */; }; 6A6AEB961A93874F002573D3 /* BasicTypesTestsFromJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A6AEB951A93874F002573D3 /* BasicTypesTestsFromJSON.swift */; }; @@ -180,6 +183,7 @@ 6A3774331A31427F00CC0AB5 /* BasicTypesTestsToJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BasicTypesTestsToJSON.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 6A412A161BAC770C001C3F67 /* ClassClusterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClassClusterTests.swift; sourceTree = ""; }; 6A412A231BB0DA26001C3F67 /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceTests.swift; sourceTree = ""; }; + 6A442CA01CE251F100AB4F1F /* MapContextTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapContextTests.swift; sourceTree = ""; }; 6A51372B1AADDE2700B82516 /* DateFormatterTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateFormatterTransform.swift; sourceTree = ""; }; 6A51372E1AADE12C00B82516 /* CustomTransformTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CustomTransformTests.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 6A6AEB951A93874F002573D3 /* BasicTypesTestsFromJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicTypesTestsFromJSON.swift; sourceTree = ""; }; @@ -338,6 +342,7 @@ 3BAD2C0F1BDDC0B000E6B203 /* MappableExtensionsTests.swift */, 6A0BF1FE1C0B53470083D1AF /* ToObjectTests.swift */, 891804CC1C122AF000E5C3EE /* MappableTypesWithTransformsTests.swift */, + 6A442CA01CE251F100AB4F1F /* MapContextTests.swift */, 84D4F8561CC3B71B008B0FB6 /* NSDecimalNumberTransformTests.swift */, 6AAC8F8319F03C2900E7A677 /* Supporting Files */, ); @@ -681,6 +686,7 @@ files = ( 6AA1F66F1BE9921C006EF513 /* MappableExtensionsTests.swift in Sources */, 891804CF1C122AF000E5C3EE /* MappableTypesWithTransformsTests.swift in Sources */, + 6A442CA31CE251F100AB4F1F /* MapContextTests.swift in Sources */, 6AA1F66B1BE94687006EF513 /* ClassClusterTests.swift in Sources */, 6AA1F66C1BE94687006EF513 /* PerformanceTests.swift in Sources */, 6AC692411BE3FD45004C119A /* BasicTypes.swift in Sources */, @@ -746,6 +752,7 @@ files = ( 3BAD2C101BDDC0B000E6B203 /* MappableExtensionsTests.swift in Sources */, 891804CD1C122AF000E5C3EE /* MappableTypesWithTransformsTests.swift in Sources */, + 6A442CA11CE251F100AB4F1F /* MapContextTests.swift in Sources */, 6A6AEB961A93874F002573D3 /* BasicTypesTestsFromJSON.swift in Sources */, 6A0BF1FF1C0B53470083D1AF /* ToObjectTests.swift in Sources */, CD44374D1AAE9C1100A271BA /* NestedKeysTests.swift in Sources */, @@ -789,6 +796,7 @@ files = ( 3BAD2C111BDDC0B000E6B203 /* MappableExtensionsTests.swift in Sources */, 891804CE1C122AF000E5C3EE /* MappableTypesWithTransformsTests.swift in Sources */, + 6A442CA21CE251F100AB4F1F /* MapContextTests.swift in Sources */, 6AA1F66D1BE9468D006EF513 /* NestedArrayTests.swift in Sources */, 6A412A181BAC830B001C3F67 /* ClassClusterTests.swift in Sources */, CD1603261AC02480000CD69A /* BasicTypesTestsFromJSON.swift in Sources */, diff --git a/ObjectMapper/Core/FromJSON.swift b/ObjectMapper/Core/FromJSON.swift index a11f33c3..32cb48bf 100755 --- a/ObjectMapper/Core/FromJSON.swift +++ b/ObjectMapper/Core/FromJSON.swift @@ -48,8 +48,8 @@ internal final class FromJSON { /// Mappable object class func object(inout field: N, map: Map) { if map.toObject { - Mapper().map(map.currentValue, toObject: field) - } else if let value: N = Mapper().map(map.currentValue) { + Mapper(context: map.context).map(map.currentValue, toObject: field) + } else if let value: N = Mapper(context: map.context).map(map.currentValue) { field = value } } @@ -57,31 +57,31 @@ internal final class FromJSON { /// Optional Mappable Object class func optionalObject(inout field: N?, map: Map) { if let field = field where map.toObject && map.currentValue != nil { - Mapper().map(map.currentValue, toObject: field) + Mapper(context: map.context).map(map.currentValue, toObject: field) } else { - field = Mapper().map(map.currentValue) + field = Mapper(context: map.context).map(map.currentValue) } } /// Implicitly unwrapped Optional Mappable Object class func optionalObject(inout field: N!, map: Map) { if let field = field where map.toObject && map.currentValue != nil { - Mapper().map(map.currentValue, toObject: field) + Mapper(context: map.context).map(map.currentValue, toObject: field) } else { - field = Mapper().map(map.currentValue) + field = Mapper(context: map.context).map(map.currentValue) } } /// mappable object array class func objectArray(inout field: Array, map: Map) { - if let objects = Mapper().mapArray(map.currentValue) { + if let objects = Mapper(context: map.context).mapArray(map.currentValue) { field = objects } } /// optional mappable object array class func optionalObjectArray(inout field: Array?, map: Map) { - if let objects: Array = Mapper().mapArray(map.currentValue) { + if let objects: Array = Mapper(context: map.context).mapArray(map.currentValue) { field = objects } else { field = nil @@ -90,7 +90,7 @@ internal final class FromJSON { /// Implicitly unwrapped optional mappable object array class func optionalObjectArray(inout field: Array!, map: Map) { - if let objects: Array = Mapper().mapArray(map.currentValue) { + if let objects: Array = Mapper(context: map.context).mapArray(map.currentValue) { field = objects } else { field = nil @@ -99,27 +99,27 @@ internal final class FromJSON { /// mappable object array class func twoDimensionalObjectArray(inout field: Array>, map: Map) { - if let objects = Mapper().mapArrayOfArrays(map.currentValue) { + if let objects = Mapper(context: map.context).mapArrayOfArrays(map.currentValue) { field = objects } } /// optional mappable 2 dimentional object array class func optionalTwoDimensionalObjectArray(inout field: Array>?, map: Map) { - field = Mapper().mapArrayOfArrays(map.currentValue) + field = Mapper(context: map.context).mapArrayOfArrays(map.currentValue) } /// Implicitly unwrapped optional 2 dimentional mappable object array class func optionalTwoDimensionalObjectArray(inout field: Array>!, map: Map) { - field = Mapper().mapArrayOfArrays(map.currentValue) + field = Mapper(context: map.context).mapArrayOfArrays(map.currentValue) } /// Dctionary containing Mappable objects class func objectDictionary(inout field: Dictionary, map: Map) { if map.toObject { - Mapper().mapDictionary(map.currentValue, toDictionary: field) + Mapper(context: map.context).mapDictionary(map.currentValue, toDictionary: field) } else { - if let objects = Mapper().mapDictionary(map.currentValue) { + if let objects = Mapper(context: map.context).mapDictionary(map.currentValue) { field = objects } } @@ -128,53 +128,53 @@ internal final class FromJSON { /// Optional dictionary containing Mappable objects class func optionalObjectDictionary(inout field: Dictionary?, map: Map) { if let field = field where map.toObject && map.currentValue != nil { - Mapper().mapDictionary(map.currentValue, toDictionary: field) + Mapper(context: map.context).mapDictionary(map.currentValue, toDictionary: field) } else { - field = Mapper().mapDictionary(map.currentValue) + field = Mapper(context: map.context).mapDictionary(map.currentValue) } } /// Implicitly unwrapped Dictionary containing Mappable objects class func optionalObjectDictionary(inout field: Dictionary!, map: Map) { if let field = field where map.toObject && map.currentValue != nil { - Mapper().mapDictionary(map.currentValue, toDictionary: field) + Mapper(context: map.context).mapDictionary(map.currentValue, toDictionary: field) } else { - field = Mapper().mapDictionary(map.currentValue) + field = Mapper(context: map.context).mapDictionary(map.currentValue) } } /// Dictionary containing Array of Mappable objects class func objectDictionaryOfArrays(inout field: Dictionary, map: Map) { - if let objects = Mapper().mapDictionaryOfArrays(map.currentValue) { + if let objects = Mapper(context: map.context).mapDictionaryOfArrays(map.currentValue) { field = objects } } /// Optional Dictionary containing Array of Mappable objects class func optionalObjectDictionaryOfArrays(inout field: Dictionary?, map: Map) { - field = Mapper().mapDictionaryOfArrays(map.currentValue) + field = Mapper(context: map.context).mapDictionaryOfArrays(map.currentValue) } /// Implicitly unwrapped Dictionary containing Array of Mappable objects class func optionalObjectDictionaryOfArrays(inout field: Dictionary!, map: Map) { - field = Mapper().mapDictionaryOfArrays(map.currentValue) + field = Mapper(context: map.context).mapDictionaryOfArrays(map.currentValue) } /// mappable object Set class func objectSet(inout field: Set, map: Map) { - if let objects = Mapper().mapSet(map.currentValue) { + if let objects = Mapper(context: map.context).mapSet(map.currentValue) { field = objects } } /// optional mappable object array class func optionalObjectSet(inout field: Set?, map: Map) { - field = Mapper().mapSet(map.currentValue) + field = Mapper(context: map.context).mapSet(map.currentValue) } /// Implicitly unwrapped optional mappable object array class func optionalObjectSet(inout field: Set!, map: Map) { - field = Mapper().mapSet(map.currentValue) + field = Mapper(context: map.context).mapSet(map.currentValue) } } diff --git a/ObjectMapper/Core/Map.swift b/ObjectMapper/Core/Map.swift index 7395191f..1683ef70 100644 --- a/ObjectMapper/Core/Map.swift +++ b/ObjectMapper/Core/Map.swift @@ -29,6 +29,11 @@ import Foundation +/// MapContext is available for developers who wish to pass information around during the mapping process. +public protocol MapContext { + +} + /// A class used for holding mapping data public final class Map { public let mappingType: MappingType @@ -36,6 +41,7 @@ public final class Map { public internal(set) var JSONDictionary: [String : AnyObject] = [:] public internal(set) var isKeyPresent = false public var currentValue: AnyObject? + public var context: MapContext? var currentKey: String? var keyIsNested = false @@ -44,10 +50,11 @@ public final class Map { /// Counter for failing cases of deserializing values to `let` properties. private var failedCount: Int = 0 - public init(mappingType: MappingType, JSONDictionary: [String : AnyObject], toObject: Bool = false) { + public init(mappingType: MappingType, JSONDictionary: [String : AnyObject], toObject: Bool = false, context: MapContext? = nil) { self.mappingType = mappingType self.JSONDictionary = JSONDictionary self.toObject = toObject + self.context = context } /// Sets the current mapper value and key. @@ -66,7 +73,8 @@ public final class Map { // check if a value exists for the current key // do this pre-check for performance reasons if nested == false { - let object = JSONDictionary[key], isNSNull = object is NSNull + let object = JSONDictionary[key] + let isNSNull = object is NSNull isKeyPresent = isNSNull ? true : object != nil currentValue = isNSNull ? nil : object } else { diff --git a/ObjectMapper/Core/Mappable.swift b/ObjectMapper/Core/Mappable.swift index 4fa79d35..6e7343ca 100644 --- a/ObjectMapper/Core/Mappable.swift +++ b/ObjectMapper/Core/Mappable.swift @@ -9,16 +9,22 @@ import Foundation public protocol Mappable { + /// This function can be used to validate JSON prior to mapping. Return nil to cancel mapping at this point init?(_ map: Map) + /// 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 MappableCluster: Mappable { + /// This is an optional function that can 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 static func objectForMapping(map: Map) -> Mappable? } public extension Mappable { + public static func objectForMapping(map: Map) -> Mappable? { + return nil + } + /// Initializes object from a JSON String public init?(JSONString: String) { if let obj: Self = Mapper().map(JSONString) { diff --git a/ObjectMapper/Core/Mapper.swift b/ObjectMapper/Core/Mapper.swift index 88f11903..90f42212 100755 --- a/ObjectMapper/Core/Mapper.swift +++ b/ObjectMapper/Core/Mapper.swift @@ -36,7 +36,11 @@ public enum MappingType { /// The Mapper class provides methods for converting Model objects to JSON and methods for converting JSON to Model objects public final class Mapper { - public init(){} + public var context: MapContext? + + public init(context: MapContext? = nil){ + self.context = context + } // MARK: Mapping functions that map to an existing object toObject @@ -61,7 +65,7 @@ public final class Mapper { /// Usefull for those pesky objects that have crappy designated initializers like NSManagedObject public func map(JSONDictionary: [String : AnyObject], toObject object: N) -> N { var mutableObject = object - let map = Map(mappingType: .FromJSON, JSONDictionary: JSONDictionary, toObject: true) + let map = Map(mappingType: .FromJSON, JSONDictionary: JSONDictionary, toObject: true, context: context) mutableObject.mapping(map) return mutableObject } @@ -102,20 +106,20 @@ public final class Mapper { /// Maps a JSON dictionary to an object that conforms to Mappable public func map(JSONDictionary: [String : AnyObject]) -> N? { - let map = Map(mappingType: .FromJSON, JSONDictionary: JSONDictionary) + let map = Map(mappingType: .FromJSON, JSONDictionary: JSONDictionary, context: context) - // check if N is of type MappableCluster - if let klass = N.self as? MappableCluster.Type { - if var object = klass.objectForMapping(map) as? N { - object.mapping(map) - return object - } + // check if objectForMapping returns an object for mapping + if var object = N.self.objectForMapping(map) as? N { + object.mapping(map) + return object } + // fall back to using init? to create N if var object = N(map) { object.mapping(map) return object } + return nil } @@ -203,9 +207,9 @@ public final class Mapper { var mutableDictionary = dictionary for (key, value) in JSONDictionary { if let object = dictionary[key] { - Mapper().map(value, toObject: object) + Mapper(context: context).map(value, toObject: object) } else { - mutableDictionary[key] = Mapper().map(value) + mutableDictionary[key] = Mapper(context: context).map(value) } } @@ -295,7 +299,7 @@ extension Mapper { ///Maps an object that conforms to Mappable to a JSON dictionary public func toJSON( object: N) -> [String : AnyObject] { var mutableObject = object - let map = Map(mappingType: .ToJSON, JSONDictionary: [:]) + let map = Map(mappingType: .ToJSON, JSONDictionary: [:], context: context) mutableObject.mapping(map) return map.JSONDictionary } diff --git a/ObjectMapper/Core/ToJSON.swift b/ObjectMapper/Core/ToJSON.swift index 172f2b4e..8b159711 100644 --- a/ObjectMapper/Core/ToJSON.swift +++ b/ObjectMapper/Core/ToJSON.swift @@ -100,7 +100,7 @@ internal final class ToJSON { } class func object(field: N, map: Map) { - setValue(Mapper().toJSON(field), map: map) + setValue(Mapper(context: map.context).toJSON(field), map: map) } class func optionalObject(field: N?, map: Map) { @@ -110,7 +110,7 @@ internal final class ToJSON { } class func objectArray(field: Array, map: Map) { - let JSONObjects = Mapper().toJSONArray(field) + let JSONObjects = Mapper(context: map.context).toJSONArray(field) setValue(JSONObjects, map: map) } @@ -124,7 +124,7 @@ internal final class ToJSON { class func twoDimensionalObjectArray(field: Array>, map: Map) { var array = [[[String : AnyObject]]]() for innerArray in field { - let JSONObjects = Mapper().toJSONArray(innerArray) + let JSONObjects = Mapper(context: map.context).toJSONArray(innerArray) array.append(JSONObjects) } setValue(array, map: map) @@ -137,7 +137,7 @@ internal final class ToJSON { } class func objectSet(field: Set, map: Map) { - let JSONObjects = Mapper().toJSONSet(field) + let JSONObjects = Mapper(context: map.context).toJSONSet(field) setValue(JSONObjects, map: map) } @@ -149,7 +149,7 @@ internal final class ToJSON { } class func objectDictionary(field: Dictionary, map: Map) { - let JSONObjects = Mapper().toJSONDictionary(field) + let JSONObjects = Mapper(context: map.context).toJSONDictionary(field) setValue(JSONObjects, map: map) } @@ -161,7 +161,7 @@ internal final class ToJSON { } class func objectDictionaryOfArrays(field: Dictionary, map: Map) { - let JSONObjects = Mapper().toJSONDictionaryOfArrays(field) + let JSONObjects = Mapper(context: map.context).toJSONDictionaryOfArrays(field) setValue(JSONObjects, map: map) } diff --git a/ObjectMapperTests/BasicTypes.swift b/ObjectMapperTests/BasicTypes.swift index 191dc0f6..db3a468e 100644 --- a/ObjectMapperTests/BasicTypes.swift +++ b/ObjectMapperTests/BasicTypes.swift @@ -234,7 +234,12 @@ class TestCollectionOfPrimitives : Mappable { } required init?(_ map: Map){ - + if map["value"].value() == nil { + + } + if map.JSONDictionary["value"] == nil { + + } } func mapping(map: Map) { diff --git a/ObjectMapperTests/ClassClusterTests.swift b/ObjectMapperTests/ClassClusterTests.swift index eb02c166..efe2f614 100644 --- a/ObjectMapperTests/ClassClusterTests.swift +++ b/ObjectMapperTests/ClassClusterTests.swift @@ -59,11 +59,11 @@ class ClassClusterTests: XCTestCase { } } -class Vehicle: MappableCluster { +class Vehicle: Mappable { var type: String? - static func objectForMapping(map: Map) -> Mappable? { + class func objectForMapping(map: Map) -> Mappable? { if let type: String = map["type"].value() { switch type { case "car": @@ -90,6 +90,10 @@ class Car: Vehicle { var name: String? + override class func objectForMapping(map: Map) -> Mappable? { + return nil + } + override func mapping(map: Map) { super.mapping(map) diff --git a/ObjectMapperTests/MapContextTests.swift b/ObjectMapperTests/MapContextTests.swift new file mode 100644 index 00000000..a466d5d6 --- /dev/null +++ b/ObjectMapperTests/MapContextTests.swift @@ -0,0 +1,64 @@ +// +// MapContextTests.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2016-05-10. +// Copyright © 2016 hearst. All rights reserved. +// + +import XCTest +import ObjectMapper + +class MapContextTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testMappingWithContext() { + let JSON = ["name":"Tristan"] + let context = Context(shouldMap: true) + + let person = Mapper(context: context).map(JSON) + + XCTAssertNotNil(person) + XCTAssertNotNil(person?.name) + } + + func testMappingWithoutContext() { + let JSON = ["name" : "Tristan"] + + let person = Mapper().map(JSON) + + XCTAssertNotNil(person) + XCTAssertNil(person?.name) + } + + struct Context: MapContext { + var shouldMap = false + + init(shouldMap: Bool){ + self.shouldMap = shouldMap + } + } + + class Person: Mappable { + var name: String? + + required init?(_ map: Map){ + + } + + func mapping(map: Map) { + if (map.context as? Context)?.shouldMap == true { + name <- map["name"] + } + } + } +} diff --git a/ObjectMapperTests/PerformanceTests.swift b/ObjectMapperTests/PerformanceTests.swift index 66f00064..0bbe3ec8 100644 --- a/ObjectMapperTests/PerformanceTests.swift +++ b/ObjectMapperTests/PerformanceTests.swift @@ -101,7 +101,7 @@ class Person: Mappable { } } -class PersonCluster: MappableCluster { +class PersonCluster: Mappable { var username: String = "" var identifier: String? diff --git a/README.md b/README.md index ae0765e2..4f5c8593 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ ObjectMapper is a framework written in Swift that makes it easy for you to conve - [Custom Transformations](#custom-transforms) - [Subclassing](#subclasses) - [Generic Objects](#generic-objects) +- [Mapping Context](#mapping-context) - [ObjectMapper + Alamofire](#objectmapper--alamofire) - [ObjectMapper + Realm](#objectmapper--realm) - [To Do](#to-do) @@ -29,8 +30,9 @@ ObjectMapper is a framework written in Swift that makes it easy for you to conve To support mapping, a class or struct just needs to implement the ```Mappable``` protocol. ```swift public protocol Mappable { - init?(_ map: Map) + init?(_ map: Map) mutating func mapping(map: Map) + static func objectForMapping(map: Map) -> Mappable? // Optional } ``` ObjectMapper uses the ```<-``` operator to define how each member variable maps to and from JSON. @@ -46,9 +48,9 @@ class User: Mappable { var friends: [User]? // Array of Users var birthday: NSDate? - required init?(_ map: Map) { + required init?(_ map: Map) { - } + } // Mappable func mapping(map: Map) { @@ -110,10 +112,11 @@ ObjectMapper can map classes composed of the following types: ## `Mappable` Protocol -The failable initializer in the `Mappable` protocol is designed to be used for validation prior to object serialization. Returning nil within the function will prevent mapping from occuring for the object in question. +#### `init?(_ map: Map)` +This failable initializer can be used for JSON validation 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. See two approaches to do this below: ``` required init?(_ map: Map){ - // check if a required JSON property exists within the JSON. There are two ways you can inspect the JSON object. See below + // check if a required "name" property exists within the JSON. if map["name"].value() == nil { return nil } @@ -123,7 +126,13 @@ required init?(_ map: Map){ } ``` -The `mapping(map: Map)` function is where all mapping definitions should go. When parsing JSON, it is executed right after successful object initialization. When generating JSON, it is the only function that is called on the object. +#### `mutating func mapping(map: Map)` +This function is where all mapping definitions should go. When parsing JSON, it is executed after a successful object initialization. When generating JSON, it is the only function that is called on the object. + +#### `static func objectForMapping(map: Map) -> Mappable?` +This is an optional function. If it is implemented, `init?(_ map: Map)` will no longer be called by ObjectMapper. This function should be used to: +- provide an existing cached object to be used for mapping +- return an object of another type (which also 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 mapping ([see example](https://github.com/Hearst-DD/ObjectMapper/blob/master/ObjectMapperTests/ClassClusterTests.swift#L62)) # Easy Mapping of Nested Objects ObjectMapper supports dot notation within keys for easy mapping of nested objects. Given the following JSON String: @@ -244,6 +253,34 @@ class Result: Mappable { let result = Mapper>().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, simple create an object that implments `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(context: context).map(JSONString) +``` + #ObjectMapper + Alamofire If you are using [Alamofire](https://github.com/Alamofire/Alamofire) for networking and you want to convert your responses to Swift objects, you can use [AlamofireObjectMapper](https://github.com/tristanhimmelman/AlamofireObjectMapper). It is a simple Alamofire extension that uses ObjectMapper to automatically map JSON response data to Swift objects.