Search code examples
iosswiftnsurl

Runtime error while downloading and displaying JSON data


I'm trying to retrieve and show data from an api but I keep getting this really annoying runtime error and I don't know whats happening!

ViewController file:

import UIKit


class ViewController: UIViewController {
    @IBOutlet weak var valueLabel: UILabel!


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    //set corner radius of value label
    var buttonLayer: CALayer = valueLabel.layer
    buttonLayer.masksToBounds = true
    buttonLayer.cornerRadius = 5.0
    getCurrentCryptoData()
}

func getCurrentCryptoData() -> Void {
    let apiURL = NSURL(string: "https://www.allcrypt.com/api?method=cmcmarketdata")
    let sharedSession = NSURLSession.sharedSession()
    let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(apiURL, completionHandler: { (apiData: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
        let dataObject = NSData(contentsOfURL: apiData)
        let cryptoDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject, options: nil, error: nil) as NSDictionary
        let omcvalues = Current(cryptoDictionary: cryptoDictionary)
        self.valueLabel.text = "\(omcvalues.omcvalue)"

    })
    downloadTask.resume()


        }




override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

My 'current.swift' file:

import Foundation
import UIKit

struct Current {

var omcvalue: Double

init(cryptoDictionary: NSDictionary) {
    let all = cryptoDictionary["return"] as NSDictionary
    let markets = all["markets"] as NSDictionary
    let omcvalues = markets["OMC/BTC"] as NSDictionary

    omcvalue = omcvalues["low_sell"] as Double



}
}

Also this, is the api source I am trying to use: api

I am trying to get to 'OMC' values and store the 'low_sell' property but I keep getting a runtime error while running. I wonder if I'm accessing the dictionaries right, could really use with some help here!

UPDATED TO ADD INFORMATION The error I'm getting is an EXC_BREAKPOINT error. Now I know I'm looking in the right directory as when I replace 'low_sell' with 'label' it all works fine and the request goes through and is printed. It's only when I switch to low_sell.

The error code is below:

libswiftCore.dylib`swift_dynamicCastObjCClassUnconditional:
0x10af95980:  pushq  %rbp
0x10af95981:  movq   %rsp, %rbp
0x10af95984:  pushq  %rbx
0x10af95985:  pushq  %rax
0x10af95986:  movq   %rsi, %rcx
0x10af95989:  movq   %rdi, %rbx
0x10af9598c:  xorl   %eax, %eax
0x10af9598e:  testq  %rbx, %rbx
0x10af95991:  je     0x10af959ac               ;     swift_dynamicCastObjCClassUnconditional + 44
0x10af95993:  movq   0x7f236(%rip), %rsi       ; "isKindOfClass:"
0x10af9599a:  movq   %rbx, %rdi
0x10af9599d:  movq   %rcx, %rdx
0x10af959a0:  callq  0x10af9846a               ; symbol stub for: objc_msgSend
0x10af959a5:  testb  %al, %al
0x10af959a7:  movq   %rbx, %rax
0x10af959aa:  je     0x10af959b3               ;   swift_dynamicCastObjCClassUnconditional + 51
0x10af959ac:  addq   $0x8, %rsp
0x10af959b0:  popq   %rbx
0x10af959b1:  popq   %rbp
0x10af959b2:  retq   
0x10af959b3:  leaq   0xc158(%rip), %rax        ; "Swift dynamic cast failed"
0x10af959ba:  movq   %rax, 0x87427(%rip)       ; gCRAnnotations + 8
0x10af959c1:  int3   
0x10af959c2:  nopw   %cs:(%rax,%rax)

Solution

  • In the API you post, there is no "OMC/BTC" key, just "OMC\/BTC". This could have been corrected by the JSONSerialization class, but your problem is really unsolvable without more information.

    In the API results the key "low_sell" is displayed as follows:

    "low_sell": "0.00008795",
    

    Therefore, you have to first cast to String and then convert to number. It is easier with NSString:

    if let lowSellString = omcvalues["low_sell"] as? NSString {
      omcvalue = lowSellString.doubleValue
    }
    

    Note that you should always check with the above let if pattern if the key in a dictionary is present and contains valid data. doubleValue is safe in this sense because it will return 0 if it cannot successfully scan the string.