2014-11-22 19 views
7

Như bạn có thể thấy, tôi nhận được một tệp JSON, phân tích cú pháp nó bằng SwiftyJSON và cố gắng trả về tổng thời gian, nhưng nó sẽ không cho phép tôi. Làm thế nào để tôi làm điều này?Swift: Làm thế nào để trả về một giá trị trong hàm urlsession không đồng bộ?

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

btw, thay vì chỉ thay thế không gian với '+', bạn có thể xem xét thực hiện một lối thoát trăm thích hợp, như được nêu ở đây http://stackoverflow.com/a/24888789/1271826 – Rob

Trả lời

9

Bạn nên thêm tham số completionHandler đóng cửa của riêng bạn và gọi nó là khi nhiệm vụ hoàn thành:

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 
} 

Tôi cũng có điều này trả lại NSURLSessionTask trong trường hợp người gọi muốn để có thể hủy bỏ bài tập.

Dù sao, bạn muốn gọi đây là như vậy:

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

Có cách nào tôi có thể thực hiện điều này không đồng bộ không? Tôi cần nó để chờ đợi cho đến khi có một phản ứng phân tích cú pháp nhưng tôi không biết làm thế nào để làm điều đó. Giải pháp của bạn là đúng, tôi nghĩ rằng câu hỏi của tôi là sai – teo751

+0

Bạn _can, _ nhưng nó nghiêm túc cau mày. Đó là một UX khủng khiếp và nếu bạn làm điều đó vào thời điểm sai, quy trình giám sát có thể sẽ giết chết ứng dụng của bạn. Giải pháp đúng là vô hiệu hóa giao diện người dùng, trình hiển thị spinner (trong iOS, 'UIActivityIndicatorView') và đảo ngược quá trình đó khi yêu cầu được thực hiện. Bạn thực sự nên nắm lấy mô hình không đồng bộ thay vì chiến đấu với nó. – Rob

+0

Nhân tiện, thông thường mọi người sẽ gửi các trình xử lý hoàn thành đó đến hàng đợi chính (vì người gọi thường tham gia vào các cập nhật giao diện người dùng). Nếu bạn muốn tôi cập nhật câu trả lời để chỉ cho bạn cách thực hiện điều đó, hãy cho tôi biết. Nó có thể tự giải thích nếu bạn thành thạo với GCD, nhưng tôi vui mừng cho bạn thấy, nếu bạn không. – Rob

2

Một ví dụ khác:

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() 
    } 
} 

Gọi:

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

Một ví dụ khác:

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 
} 

Sau đó, tôi gọi nó trong 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)" 

      } 

     } 
    } 
Các vấn đề liên quan