Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ambigous use of mapwhen using ImmutableMappable. #749

Closed
Sajjon opened this issue Feb 15, 2017 · 4 comments
Closed

Ambigous use of mapwhen using ImmutableMappable. #749

Sajjon opened this issue Feb 15, 2017 · 4 comments

Comments

@Sajjon
Copy link

Sajjon commented Feb 15, 2017

@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.

How to use ImmutableMappable for nested objects?

And also, do I have to write a Transformer for that?

@devxoul
Copy link
Contributor

devxoul commented Feb 16, 2017

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

@Sajjon
Copy link
Author

Sajjon commented Feb 16, 2017

@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 Sajjon changed the title Nested objects using ImmutableMappable? Ambigous use of mapwhen using ImmutableMappable. Feb 16, 2017
@louisdh
Copy link

louisdh commented Feb 23, 2017

@Sajjon Btw, AlamofireObjectMapper now supports ImmutableMappable in v4.1

@tristanhimmelman
Copy link
Owner

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants