4

I want to use AlamofireObjectMapper for the first time to parse a json response in swift.

The response is:

  "success": true,
  "terms": "https:\/\/currencylayer.com\/terms",
  "privacy": "https:\/\/currencylayer.com\/privacy",
  "timestamp": 1480007048,
  "source": "USD",
  "quotes": {
    "USDAED": 3.672598,
    "USDAFN": 66.599998,
    "USDALL": 127.999937,
    "USDAMD": 478.679993,
    "USDANG": 1.780277,
    "USDAOA": 165.072998,
    "USDARS": 15.497261,
    "USDAUD": 1.348899,
    "USDAWG": 1.79,
    "USDAZN": 1.714104,
    "USDBAM": 1.855297,
    "USDBBD": 2,
    "USDBDT": 79.179735,
    "USDBGN": 1.854199,
    "USDBHD": 0.377036,
    "USDBIF": 1668.300049,
    "USDBMD": 1,
    "USDBND": 1.429902,
    "USDBOB": 6.870014,
    "USDBRL": 3.396898,
    "USDBSD": 1,
}

I mapped it like this:

class ModelCurrency:  Mappable {

    var success   : Bool?
    var terms     : String?
    var privacy   : String?
    var timestamp : CGFloat?
    var source    : String?
    var quotes    : [Quotes]?

    init() {}

    required init?(map: Map) {

    }

    func mapping(map: Map) {

         success<-map["success"]
         terms<-map["terms"]
         privacy<-map["privacy"]
         timestamp<-map["timestamp"]
         source<-map["source"]
         quotes<-map["quotes"]

        print("It json\(terms)")
    }
}

class Quotes : Mappable {

    var name : String?
    var val : CGFloat?

    required init?(map: Map) {

    }

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

And in my controller:

 override func viewDidLoad() {
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self

        super.viewDidLoad()
        let URL = "http://www.apilayer.net/api/live?access_key=ad847a0a855c0647590df2b818923025"

 Alamofire.request(URL).responseArray(queue: "quotes") { (response: DataResponse<[Quotes]>) in
            let arrayCurency = response.result.value!


                for quotes in arrayCurency {
                    print(quotes.name!)
                    print(quotes.val!)
                }

        }

    }

It gives me error mapping and this error:

cannot convert value 'String' to expected argument type 'DispatchQueue?'

enter image description here

chrki
  • 6,143
  • 6
  • 35
  • 55

2 Answers2

1

There are several issues.

  1. You want to reference DataResponse<ModelCurrency> rather than DataResponse<[Quotes]>.

  2. You want to use responseObject, not responseArray.

  3. You don't want to use that queue parameter with a String value. The queue parameter is used to specify which dispatch queue you want the completion handlers to run. But that's not what you're doing here, so you should just remove it.

  4. The value associated with the quotes key is not an array of objects. It is yet another dictionary. So you should map it to a dictionary, and then use map method to convert that to an array of Quote objects.

So, pulling that all together:

Alamofire.request(urlString).responseObject { (response: DataResponse<ModelCurrency>) in
    ...
}

And

class ModelCurrency:  Mappable {

    var success   : Bool?
    var terms     : String?
    var privacy   : String?
    var timestamp : CGFloat?
    var source    : String?
    var quotes    : [Quote]?

    required init?(map: Map) { }

    func mapping(map: Map) {

        success    <- map["success"]
        terms      <- map["terms"]
        privacy    <- map["privacy"]
        timestamp  <- map["timestamp"]
        source     <- map["source"]

        var dictionary: [String: CGFloat]?
        dictionary <- map["quotes"]
        quotes = dictionary?.map { return Quote(name: $0.key, val: $0.value) }
    }
}

class Quote {

    var name : String?
    var val : CGFloat?

    init(name: String?, val: CGFloat?) {
        self.name = name
        self.val  = val
    }

}

(I've renamed Quotes to Quote as it would appear to be a quote for a single currency.)

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I did as you said but I have an error in a row for quotes in arrayCurency error: Type ModelCurrency does not conform to protocol Sequence.What shall I do ? –  Nov 26 '16 at 22:10
  • the first i rwite responsObject i have got error : Type 'ModelCurrence' does not conform to protocol Sequence swift But i write responce Array i have got error : Value tupe ModelCurrence has not member a 'name' and 'val' –  Nov 26 '16 at 22:21
  • Alamofire.request(URL).responseObject { (response: DataResponse) in let arrayCurency = response.result.value! for quotes in arrayCurency { print(quotes.name!) print(quotes.val!) } } –  Nov 26 '16 at 22:31
  • `Alamofire.request(URL).responseObject { (response: DataResponse) in let currency = response.result.value!; for quotes in currency.quotes { print(quotes.name!); print(quotes.val!) } }` – Rob Nov 26 '16 at 22:35
  • Very well thank you for the help) I first write to Swift Everything works –  Nov 26 '16 at 22:44
  • I have another question How can I add JSON in array? and displaying array in tableView? –  Nov 27 '16 at 15:19
  • I don't understand what you mean, but rather than us trying to tease that out here in comments, I'd suggest you post a separate question. – Rob Nov 27 '16 at 15:22
  • I want array quotes displayed in tableview. How to do it ? –  Nov 27 '16 at 18:34
  • I think if you go through any modern table view tutorial, it will become self-evident. Google "Swift 3 UITableView tutorial". It's certainly too broad of a question for me to answer here. It probably isn't even a valid question for Stack Overflow. The only trick is that you have to call `tableView.reloadData()` when you're done asynchronously retrieving your quotes. – Rob Nov 27 '16 at 20:16
  • How to mapping only on certain condition. I have a login API which gives details only if user detalils are correct. other wise i will get status as "failure" . So how do mapping only on succeses ? – siva krishna Mar 10 '17 at 11:24
  • Have the `init` method return `nil` if a certain condition was met, a la https://gist.github.com/robertmryan/b91cb172dd4cff2bfc3b37766eff2d1b – Rob Mar 11 '17 at 03:00
0

The issue is with this part of code:

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

in Quotes.

What you should do is map dictionary:

var quotes: [String : CGFloat] = [:]

and when mapping use:

quotes  <- map["quotes"]

Take a look at:

https://github.com/Hearst-DD/ObjectMapper

at the basics there is mapping dictionary.

To be more specific, in quote object you don't have name and val JSON objects, it is just what you want. If you map it to dictionary you will be able to access theses values.

Haven't seen your image - but if you don't change above the app will crash.

For the above issue you need to provide queue in which you want to run your request, if you don't want to mess with that and you actually want keyPath, then you need to call function with keyPath: instead of queue:. Link:

https://github.com/tristanhimmelman/AlamofireObjectMapper

look for Array Responses

Miknash
  • 7,888
  • 3
  • 34
  • 46
  • My probleme is .responseArray(queue: "quotes") error cannot convert value 'String' to expected argument type 'DispatchQueue?' I write var quotes: [String : CGFloat] = [:] it changed nothing. var success : Bool? var terms : String? var privacy : String? var timestamp : CGFloat? var source : String? var quotes: [String : CGFloat] = [:] –  Nov 24 '16 at 18:40
  • Take a look at the rest of the answer - have you tried instead of queue to provide keyPath ? – Miknash Nov 24 '16 at 18:41