@devxoul Hi! I am trying to use the ImmutableMappable
protocol, but there is no explanation in the README of how to use together with nested objects.
I wanna try something simple like this:
struct Father: ImmutableMappable {
let name: String
let children: [Child]
init(map: Map) throws {
name = try map.value("name")
children = try map.value("children", using: ArrayTransform<Child>())
}
}
struct Child: ImmutableMappable {
let age: Int
init(map: Map) throws {
age = try map.value("age")
}
}
So there is no Transform
working with arrays? So I wrote the transformer below inspired by ListTransformer from 'ObjectMapper-Realm'
struct ArrayTransform<T: ImmutableMappable> {}
extension ArrayTransform: TransformType {
typealias Object = [T]
typealias JSON = [Any]
func transformFromJSON(_ value: Any?) -> Object? {
if let objects = Mapper<T>().mapArray(JSONObject: value) {
let list = Object()
list.append(objectsIn: objects)
return list
}
return nil
}
public func transformToJSON(_ value: Object?) -> JSON? {
return value?.flatMap { $0.toJSON() }
}
}
Results in compilation error: Ambigious use of 'mapArray(JSONObject:)'
My theory is that it is because the compiler finds the method in these two scopes:
public extension Mapper where N: ImmutableMappable
public final class Mapper<N: BaseMappable> {
But since ImmutableMappable
inherits from BaseMappable
, both functions are valid candidates.
And also, do I have to write a Transformer for that?
You don't have to use ArrayTransform stuff. Just do it as following:
init(map: Map) throws {
// ...
children = try map.value("children")
}
PS: The reason of the build failure is because you didn't mark `mapArray()` with `try`.
let objects = try Mapper().mapArray(JSONObject: value) // do something
@devxoul Hey thanks for you reply! Hehe yeah that was easier than I thought! 馃槄
Regarding your P.S.
answer - I still can't get it working! Now I am trying to implement and Alamofire + ObjectMapper extension analogously to AlamofireObjectMapper, but for ImmutableMappable
I still get compilation error Ambigious use of map....
, look for the two comments "// Compilation Error"
in code below.
What am I doing wrong?
import Foundation
import Alamofire
import ObjectMapper
extension DataRequest {
enum ErrorCode: Int {
case noData = 1
case dataSerializationFailed = 2
}
internal static func newError(_ code: ErrorCode, failureReason: String) -> NSError {
let errorDomain = "com.alamofireobjectmapper.error"
let userInfo = [NSLocalizedFailureReasonErrorKey: failureReason]
let returnError = NSError(domain: errorDomain, code: code.rawValue, userInfo: userInfo)
return returnError
}
public static func ObjectMapperSerializer<T: ImmutableMappable>(_ keyPath: String?, mapToObject object: T? = nil, context: MapContext? = nil) -> DataResponseSerializer<T> {
return DataResponseSerializer { request, response, data, error in
guard error == nil else {
return .failure(error!)
}
guard let _ = data else {
let failureReason = "Data could not be serialized. Input data was nil."
let error = newError(.noData, failureReason: failureReason)
return .failure(error)
}
let jsonResponseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments)
let result = jsonResponseSerializer.serializeResponse(request, response, data, error)
let JSONToMap: Any?
if let keyPath = keyPath , keyPath.isEmpty == false {
JSONToMap = (result.value as AnyObject?)?.value(forKeyPath: keyPath)
} else {
JSONToMap = result.value
}
if let object = object {
_ = Mapper<T>().map(JSONObject: JSONToMap, toObject: object)
return .success(object)
} else {
do {
// Compilation Error: "Amigious user of 'map(JSONObject:)'"
let parsedObject = try Mapper<T>(context: context).map(JSONObject: JSONToMap)
return .success(parsedObject)
} catch let error {
fatalError("Mapping error: \(error)")
}
}
let failureReason = "ObjectMapper failed to serialize response."
let error = newError(.dataSerializationFailed, failureReason: failureReason)
return .failure(error)
}
}
@discardableResult
public func responseObject<T: ImmutableMappable>(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<T>) -> Void) -> Self {
return response(queue: queue, responseSerializer: DataRequest.ObjectMapperSerializer(keyPath, mapToObject: object, context: context), completionHandler: completionHandler)
}
public static func ObjectMapperArraySerializer<T: ImmutableMappable>(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer<[T]> {
return DataResponseSerializer { request, response, data, error in
guard error == nil else {
return .failure(error!)
}
guard let _ = data else {
let failureReason = "Data could not be serialized. Input data was nil."
let error = newError(.dataSerializationFailed, failureReason: failureReason)
return .failure(error)
}
let jsonResponseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments)
let result = jsonResponseSerializer.serializeResponse(request, response, data, error)
let JSONToMap: Any?
if let keyPath = keyPath, keyPath.isEmpty == false {
JSONToMap = (result.value as AnyObject?)?.value(forKeyPath: keyPath)
} else {
JSONToMap = result.value
}
do {
// Compilation Error: "Amigious user of 'map(JSONObject:)'"
let parsedObject = try Mapper<T>(context: context).mapArray(JSONObject: JSONToMap)
return .success(parsedObject)
} catch let error {
fatalError("Failed to map, error: \(error)")
}
let failureReason = "ObjectMapper failed to serialize response."
let error = newError(.dataSerializationFailed, failureReason: failureReason)
return .failure(error)
}
}
@discardableResult
public func responseArray<T: ImmutableMappable>(queue: DispatchQueue? = nil, keyPath: String? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self {
return response(queue: queue, responseSerializer: DataRequest.ObjectMapperArraySerializer(keyPath, context: context), completionHandler: completionHandler)
}
}
@Sajjon Btw, AlamofireObjectMapper now supports ImmutableMappable
in v4.1
Closing this as the new version of AlamofireObjectMapper should take care of the problem. Feel free to comment and I can reopen the ticket if needed.
Most helpful comment
@Sajjon Btw, AlamofireObjectMapper now supports
ImmutableMappable
in v4.1