1

I am working on an app that displays the live Bitcoin price. I am using 2 APIs to do this - one plaintext, and one JSON. I am having a bit of trouble with the JSON API.

Here's a bit of my Swift code

func BTCFallback(){

    var string2 = currencySelector.currentTitle


    var url = NSURL(string:"https://bitpay.com/api/rates/" +  (string2)!)
    var request = NSURLRequest(URL: url)


    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:fallback)

    var data = NSData(contentsOfURL:url);
    let value = NSString(string: USD.text).doubleValue / NSString(data:data, encoding:NSUTF8StringEncoding).doubleValue

    // Define JSON string
    var JSONString = "\(data)"

    // Get NSData using string
    if let JSONData = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {

        // Parse JSONData into JSON object
        var parsingError: NSError?
    if let JSONObject = NSJSONSerialization.JSONObjectWithData(JSONData, options: nil, error: &parsingError) as? [String: AnyObject] {

        // If the parsing was successful grab the rate object
        var rateObject: AnyObject? = JSONObject["rate"]

        // Make sure the rate object is the expected type
        if let rate = rateObject as? Float {
            println("rate is \(rate)")
            BTC.text = "\(rate)"
        }
    } else {

        // There was an error parsing the JSON data
        println("Error parsing JSON: \(parsingError)")
        BTC.text = "err1"
    }

}






}

In the above code, currencySelector.currentTitle is equal to an ISO currency code, for instance USD. BTC.text is a UI element.

The expected behavior is that the code will set the counterpart of "rate" as the text of BTC.text. In case this helps, the API returns something like {"code":"USD","name":"US Dollar","rate":376.71}. I would want, using the above example, to have BTC.text set to 376.71

Here's what's happening: the consoe gives the error Error parsing JSON: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x16eb0f60 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})

What am I doing wrong? Thanks in advance!

13
  • What does the data look like before it is passed into the parser? Commented Oct 24, 2014 at 15:26
  • 1. Why are you converting the data to a string and then back to data prior to JSONObjectWithData? 2. println the JSON string JSONString and examine the JSON and verify that it is valid JSON. Commented Oct 24, 2014 at 15:27
  • @Hyperbole The JSON looks like {"code":"USD","name":"US Dollar","rate":376.71} from the API. A link to the API is bitpay.com/api/rates/USD Commented Oct 24, 2014 at 15:28
  • @rocket101 It can't look like that, otherwise the parser wouldn't barf. Make sure you're actually passing a data object that has data in it. Put a breakpoint after dataUsingEncoding() and check it there. Commented Oct 24, 2014 at 15:31
  • 1
    @rocket101 Yeah, that's the string encoded. Is there a reason why you're not passing the NSData object from the contentsOfURL call directly into JSONObjectWithData()? Something might be lost in translation. Commented Oct 24, 2014 at 15:42

1 Answer 1

3

It is all a matter of handling the returned data and de-serialization.

Here is example code, note that the handling of Optionals should be better, this is just to demonstrate the basic code. For example purposes I used a simple synchronous web call.:

var url: NSURL! = NSURL(string:"https://bitpay.com/api/rates/AUD")
var request = NSURLRequest(URL: url)
var response: NSURLResponse?
var error: NSError?
var data: NSData? = NSURLConnection.sendSynchronousRequest(request, returningResponse:&response, error:&error)
println("data: \(data)")

if let data: NSData = NSURLConnection.sendSynchronousRequest(request, returningResponse:&response, error:&error) {
    println("data: \(data)")

    var parsingError: NSError?
    if let rateDictionary = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &parsingError) as NSDictionary? {
        println("rateDictionary: \(rateDictionary)")

        // If the parsing was successful grab the rate object
        if var rateString: AnyObject = rateDictionary["rate"] {
            println("rateString: \(rateString)")

            // Make sure the rate object is the expected type
            if let rate = rateString.floatValue {
                println("rate is \(rate)")
            }
        }
    }
}

Ouput:

data: Optional(7b22636f 6465223a 22415544 222c226e 616d6522 3a224175 73747261 6c69616e 20446f6c 6c617222 2c227261 7465223a 3430372e 39393137 7d)

rateDictionary: {
    code = AUD;
    name = "Australian Dollar";
    rate = "407.9917";
}

rateString: 407.9917

rate is 407.992

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.