2014-11-22 91 views
7

正如你所看到的,我收到一個JSON文件,使用SwiftyJSON解析它,並試圖返回totalTime,但它不會讓我。我該怎麼做呢?Swift:如何在異步的urlsession函數中返回一個值?

func googleDuration(origin: String, destination: String) -> Int{ 
    // do calculations origin and destiantion with google distance matrix api 

    let originFix = origin.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.LiteralSearch, range: nil); 
    let destinationFix = destination.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.LiteralSearch, range: nil); 

    let urlAsString = "https://maps.googleapis.com/maps/api/distancematrix/json?origins="+originFix+"&destinations="+destinationFix; 
    println(urlAsString); 

    let url = NSURL(string: urlAsString)! 
    let urlSession = NSURLSession.sharedSession() 

    let task = urlSession.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in 
     if error != nil { 
      // If there is an error in the web request, print it to the console 
      println(error.localizedDescription) 
     } 

     println("parsing JSON"); 
     let json = JSON(data: data); 
     if (json["status"].stringValue == "OK") { 
      if let totalTime = json["rows"][0]["elements"][0]["duration"]["value"].integerValue { 
       println(totalTime); 
      } 
     } 
    }) 
    task.resume(); 
} 
+0

順便說一句,而不是僅僅用'+'代替空格,你可能會考慮做適當的百分之逃跑,這裏http://stackoverflow.com/a/24888789概述/ 1271826 – Rob 2014-11-23 11:59:18

回答

9

你應該添加自己的completionHandler關閉參數,當任務完成後調用它:

func googleDuration(origin: String, destination: String, completionHandler: (Int?, NSError?) -> Void) -> NSURLSessionTask { 
    // do calculations origin and destiantion with google distance matrix api 

    let originFix = origin.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.LiteralSearch, range: nil); 
    let destinationFix = destination.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.LiteralSearch, range: nil); 

    let urlAsString = "https://maps.googleapis.com/maps/api/distancematrix/json?origins="+originFix+"&destinations="+destinationFix 
    println(urlAsString) 

    let url = NSURL(string: urlAsString)! 
    let urlSession = NSURLSession.sharedSession() 

    let task = urlSession.dataTaskWithURL(url) { data, response, error -> Void in 
     if error != nil { 
      // If there is an error in the web request, print it to the console 
      // println(error.localizedDescription) 
      completionHandler(nil, error) 
      return 
     } 

     //println("parsing JSON"); 
     let json = JSON(data: data) 
     if (json["status"].stringValue == "OK") { 
      if let totalTime = json["rows"][0]["elements"][0]["duration"]["value"].integerValue { 
       // println(totalTime); 
       completionHandler(totalTime, nil) 
       return 
      } 
      let totalTimeError = NSError(domain: kAppDomain, code: kTotalTimeError, userInfo: nil) // populate this any way you prefer 
      completionHandler(nil, totalTimeError) 
     } 
     let jsonError = NSError(domain: kAppDomain, code: kJsonError, userInfo: nil) // again, populate this as you prefer 
     completionHandler(nil, jsonError) 
    } 
    task.resume() 
    return task 
} 

我也不得不在這種情況下,返回NSURLSessionTask調用者希望能夠取消任務。

無論如何,你會調用這個像這樣:

googleDuration(origin, destination: destination) { totalTime, error in 
    if let totalTime = totalTime { 
     // use totalTime here 
    } else { 
     // handle error  
    } 
} 
+0

有什麼辦法可以讓這個非異步?我需要它等到解析出響應,但我不知道如何去做。你的解決方案是對的,我認爲我的問題只是錯誤 – teo751 2014-11-22 21:50:09

+0

你可以,但它是嚴重皺眉。這是一個可怕的用戶體驗,如果你在錯誤的時間這樣做,看門狗進程可能會立即終止你的應用程序。正確的解決方案是禁用UI,呈現微調器(在iOS中是'UIActivityIndi​​catorView'),並在請求完成時逆轉該過程。你真的應該擁抱異步模式而不是與之搏鬥。 – Rob 2014-11-22 22:02:28

+0

順便說一句,通常人們會派遣這些完成處理程序到主隊列中(因爲調用者通常從事UI更新)。如果你想讓我更新答案,告訴你如何做到這一點,讓我知道。如果你精通GCD,這可能是自我解釋,但如果你不是,我很高興向你展示。 – Rob 2014-11-22 22:04:44

2

又如:

class func getExchangeRate(#baseCurrency: String, foreignCurrency:String, completion: ((result:Double?) -> Void)!){ 
    let baseURL = kAPIEndPoint 
    let query = String(baseCurrency)+"_"+String(foreignCurrency) 

    var finalExchangeRate = 0.0 
    if let url = NSURL(string: baseURL + query) { 
     NSURLSession.sharedSession().dataTaskWithURL(url) { data, response, error in 

      if ((data) != nil) { 
       let jsonDictionary:NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: nil) as NSDictionary 

       if let results = jsonDictionary["results"] as? NSDictionary{ 
        if let queryResults = results[query] as? NSDictionary{ 
         if let exchangeRate = queryResults["val"] as? Double{ 
          let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT 
          dispatch_async(dispatch_get_global_queue(priority, 0)) { 
           dispatch_async(dispatch_get_main_queue()) { 
            completion(result: exchangeRate) 
           } 
          } 

         } 
        } 
       } 
      } 
      else { 
       completion(result: nil) 
      } 

     }.resume() 
    } 
} 

電話:

Currency.getExchangeRate(baseCurrency: "USD", foreignCurrency: "EUR") { (result) -> Void in 
     if let exchangeValue = result { 
      print(exchangeValue) 
     } 
    } 
0

又如:

func getJason(url: NSURL, completionHandler: (String?, NSError?) -> Void) -> NSURLSessionTask { 

    var finalData: String! 
    let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in 

     if error != nil{ 

      completionHandler(nil, error) 
      return 
     } 
     else{ 

     if let urlContent = data{ 

      do{ 
       let jsonData = try NSJSONSerialization.JSONObjectWithData(urlContent, options: NSJSONReadingOptions.MutableContainers) 

       if let ip = jsonData["ip"]{ 

        finalData = ip as? String 
        completionHandler(finalData, nil) 
        return 
       } 

      }catch{ 
       print("EMPTY") 
      } 

     } 

    } 
} 
    task.resume() 
    return task 
} 

然後,我把它叫做在viewDidLoad中

getJason(url) { (ipAddress, error) -> Void in 

     if error != nil{ 

      print(error) 
     } 
     else{ 
      if let ip = ipAddress{   //To get rid of optional 

     self.ipLabelDisplay.text = "Your Ip Address is: \(ip)" 

      } 

     } 
    } 
相關問題