classUser: 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?
let transform =TransformOf<Int, String>(fromJSON: { (value: String?) -> Int? in }, toJSON: { (value: Int?) -> String? in // transform value from Int? to String? iflet value = value { returnString(value) } returnnil })
funcmapping(map: Map) { id <- (map["id"], transform) }
/// BaseMappable should not be implemented directly. Mappable or StaticMappable should be used instead publicprotocolBaseMappable { /// This function is where all variable mappings should occur. It is executed by Mapper during the mapping (serialization and deserialization) process. mutatingfuncmapping(map: Map) }
publicprotocolMappable: BaseMappable { /// This function can be used to validate JSON prior to mapping. Return nil to cancel mapping at this point init?(map: Map) }
publicextensionBaseMappable { /// Initializes object from a JSON String publicinit?(JSONString: String, context: MapContext? =nil) { iflet obj: Self=Mapper(context: context).map(JSONString: JSONString) { self= obj } else { returnnil } } /// Initializes object from a JSON Dictionary publicinit?(JSON: [String: Any], context: MapContext? =nil) { iflet obj: Self=Mapper(context: context).map(JSON: JSON) { self= obj } else { returnnil } } /// Returns the JSON Dictionary for the object publicfunctoJSON() -> [String: Any] { returnMapper().toJSON(self) } /// Returns the JSON String for the object publicfunctoJSONString(prettyPrint: Bool=false) -> String? { returnMapper().toJSONString(self, prettyPrint: prettyPrint) } }
BaseMappable为实现 Mappable 的 Model 提供了四种实例方法,有两个是初始化方法,当然你也可以自己新建一个 Mapper 来初始化;还有两个是 Model 转 JSON 的方法。
extensionMapper { // MARK: Functions that create JSON from objects ///Maps an object that conforms to Mappable to a JSON dictionary <String, Any> publicfunctoJSON(_object: N) -> [String: Any] { var mutableObject = object let map =Map(mappingType: .toJSON, JSON: [:], context: context, shouldIncludeNilValues: shouldIncludeNilValues) mutableObject.mapping(map: map) return map.JSON } ///Maps an array of Objects to an array of JSON dictionaries [[String: Any]] publicfunctoJSONArray(_array: [N]) -> [[String: Any]] { return array.map { // convert every element in array to JSON dictionary equivalent self.toJSON($0) } } ///Maps a dictionary of Objects that conform to Mappable to a JSON dictionary of dictionaries. publicfunctoJSONDictionary(_dictionary: [String: N]) -> [String: [String: Any]] { return dictionary.map { (arg: (key: String, value: N)) in // convert every value in dictionary to its JSON dictionary equivalent return (arg.key, self.toJSON(arg.value)) } } ///Maps a dictionary of Objects that conform to Mappable to a JSON dictionary of dictionaries. publicfunctoJSONDictionaryOfArrays(_dictionary: [String: [N]]) -> [String: [[String: Any]]] { return dictionary.map { (arg: (key: String, value: [N])) in // convert every value (array) in dictionary to its JSON dictionary equivalent return (arg.key, self.toJSONArray(arg.value)) } } /// Maps an Object to a JSON string with option of pretty formatting publicfunctoJSONString(_object: N, prettyPrint: Bool=false) -> String? { letJSONDict= toJSON(object) returnMapper.toJSONString(JSONDictasAny, prettyPrint: prettyPrint) }
/// Maps an array of Objects to a JSON string with option of pretty formatting publicfunctoJSONString(_array: [N], prettyPrint: Bool=false) -> String? { letJSONDict= toJSONArray(array) returnMapper.toJSONString(JSONDictasAny, prettyPrint: prettyPrint) } /// Converts an Object to a JSON string with option of pretty formatting publicstaticfunctoJSONString(_JSONObject: Any, prettyPrint: Bool) -> String? { let options: JSONSerialization.WritingOptions= prettyPrint ? .prettyPrinted : [] ifletJSON=Mapper.toJSONData(JSONObject, options: options) { returnString(data: JSON, encoding: String.Encoding.utf8) } returnnil } /// Converts an Object to JSON data with options publicstaticfunctoJSONData(_JSONObject: Any, options: JSONSerialization.WritingOptions) -> Data? { ifJSONSerialization.isValidJSONObject(JSONObject) { letJSONData: Data? do { JSONData=tryJSONSerialization.data(withJSONObject: JSONObject, options: options) } catchlet error { print(error) JSONData=nil } returnJSONData } returnnil } }
/// Sets the current mapper value and key. /// The Key paramater can be a period separated string (ex. "distance.value") to access sub objects. publicsubscript(key: String) -> Map { // save key and value associated to it returnself.subscript(key: key) }
privatefunc`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 { let object =JSON[key] let isNSNull = object isNSNull isKeyPresent = isNSNull ?true : object !=nil currentValue = isNSNull ?nil : object } // update isKeyPresent if ignoreNil is true if ignoreNil && currentValue ==nil { isKeyPresent =false } } returnself }
/// Fetch value from JSON dictionary, loop through keyPathComponents until we reach the desired object privatefuncvalueFor(_keyPathComponents: ArraySlice<String>, dictionary: [String: Any]) -> (Bool, Any?) { // Implement it as a tail recursive function. if keyPathComponents.isEmpty { return (false, nil) } iflet keyPath = keyPathComponents.first { let isTail = keyPathComponents.count ==1 let object = dictionary[keyPath] if object isNSNull { return (isTail, nil) } elseif keyPathComponents.count >1, let dict = object as? [String: Any] { let tail = keyPathComponents.dropFirst() return valueFor(tail, dictionary: dict) } elseif keyPathComponents.count >1, let array = object as? [Any] { let tail = keyPathComponents.dropFirst() return valueFor(tail, array: array) } else { return (isTail && object !=nil, object) } } return (false, nil) }
/// Fetch value from JSON Array, loop through keyPathComponents them until we reach the desired object privatefuncvalueFor(_keyPathComponents: ArraySlice<String>, array: [Any]) -> (Bool, Any?) { // Implement it as a tail recursive function. if keyPathComponents.isEmpty { return (false, nil) } //Try to convert keypath to Int as index iflet keyPath = keyPathComponents.first, let index =Int(keyPath) , index >=0&& index < array.count { let isTail = keyPathComponents.count ==1 let object = array[index] if object isNSNull { return (isTail, nil) } elseif keyPathComponents.count >1, let array = object as? [Any] { let tail = keyPathComponents.dropFirst() return valueFor(tail, array: array) } elseif keyPathComponents.count >1, let dict = object as? [String: Any] { let tail = keyPathComponents.dropFirst() return valueFor(tail, dictionary: dict) } else { return (isTail, object) } } return (false, nil) }
structPerson { var firstName: String var lastName: String var birthDate: Date var friend: [String] var lalala: Dictionary<String, Any> var age: Int { returnCalendar.current.dateComponents([.year], from: birthDate, to: Date()).year ??-1 } } extensionPerson: AutoMappable {}