Search code examples
swiftapialamofire

Alamofire URL Request - unexpectedly found nil when unwrapping an Optional Value


So I have a PageViewController to manage various VCs that contain an array of stock symbols, prices etc.

I use Alamofire to manage the API call in my model. Here is the shorten summary of the model and its problem:

struct Stock {
    var last: String?
    var companyName: String?
    var symbol: String?

    var dataFields: [[String : String]]
}

class SwiftStock {
  class func fetchStockForListOfSymbols(#symbols: Array<String>, completion:(stock: Stock) -> ()) {

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {

      var stockURL = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22\(symbols)%22)&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&format=json"

      request(.GET, stockURL)
        .responseJSON { (_, response, resultsJSON, _) in

          if response?.statusCode == 200 {

            if let stockData = (((resultsJSON as! [String : AnyObject])["query"] as! [String : AnyObject])["results"] as! [String : AnyObject])["quote"] as? [String : AnyObject] {

              // lengthy creation, yeah
              var dataFields = [[String : String]]()

              dataFields.append(["Last" : stockData["LastTradePriceOnly"] as? String ?? "N/A"])
              dataFields.append(["Company" : stockData["Name"] as? String ?? "N/A"])
              dataFields.append(["Symbol" : stockData["Symbol"] as? String ?? "N/A"])

              let stock = Stock(
                last: dataFields[0].values.array[0],
                companyName: dataFields[1].values.array[0],
                symbol: dataFields[2].values.array[0],
                dataFields: dataFields
              )
              dispatch_async(dispatch_get_main_queue()) {
                completion(stock: stock)
              }
            }
          }
      }
    }
  }

There was an unexpectedly nil found while unwrapping an Optional value during the Alamofire's URLRequest. Not sure where I screw up. Any advice?

The codes on the PageViewController are as follows:

class PageViewController: UIPageViewController, UIPageViewControllerDataSource
{
  var symbols: Array<String> = ["CMG", "TSLA", "FB", "SHAK"]
  var prices = [""]

  var stock: Stock?

  override func viewDidLoad() {
    super.viewDidLoad()

    // Set the data source to itself
    dataSource = self

    // Create the first screen
    if let startingViewController = self.viewControllerAtIndex(0) {
      setViewControllers([startingViewController], direction: .Forward, animated: true, completion: nil)
    }
  }

  override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    updateUI()
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {

    var index = (viewController as! MainViewController).index
    index++
    return self.viewControllerAtIndex(index)
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {

    var index = (viewController as! MainViewController).index
    index--
    return self.viewControllerAtIndex(index)
  }

  func viewControllerAtIndex(index: Int) -> MainViewController? {
    if index == NSNotFound || index < 0 || index >= self.symbols.count {
      return nil
    }

    // Create a new view controller and pass suitable data.
    if let pageContentViewController = storyboard?.instantiateViewControllerWithIdentifier("PageContentViewController") as? MainViewController {
      pageContentViewController.symbol = symbols[index]
      pageContentViewController.price = prices[index]
      pageContentViewController.index = index
      pageContentViewController.pageCount = symbols.count

      return pageContentViewController
    }
    return nil
  }

  func updateUI() {

    SwiftStock.fetchStockForListOfSymbols(symbols: symbols) { (stock) -> () in

      self.prices = ["\(stock.last!)"]
    }
  } 

}

Solution

  • Your url is wrong, if you copy and paste the url into the browser its supposed to return json, but instead it returns this

    {
      error: {
      lang: "en-US",
    description: "Query syntax error(s) [line 1:54 mismatched character  '(' expecting set null,line 1:65 mismatched character ' ' expecting '"']"
    }
    }
    

    Here is the complete code without using a library to retrieve the stock symbols :

    import UIKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            let url = NSURL(string: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22CMG%22%2C%20%22TSLA%22%2C%20%22FB%22%2C%20%22SHAK%22)&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&format=json")
            let session = NSURLSession.sharedSession()
    
    
    
            let dataTask = session.dataTaskWithURL(url!) { (data, response, error) -> Void in
                if(error != nil){
                    print("Something wrong")
                }
    
                do{
                    let jsonData:NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary
                    if let quote = jsonData["query"]?["results"] as? NSDictionary {
                        if let quoteArray = quote["quote"] as? NSArray {
                            for quoteItem in quoteArray {
                                print(quoteItem["symbol"] as! NSString)
                            }
                        }
                    }
    
                } catch{
    
                }
    
    
            }
    
            dataTask?.resume()
        }
    
    
    
    
    }