2017-02-09 16 views
1

私はswift 3で私の最初のプロジェクトを作成しようとしています。非同期機能Syncronize

私のAPIからデータを取得しようとしています。これは、私が手動で関数を起動するとかなりうまくいく。非同期要求を同期する必要があります。

私は3回機能をトリガーし、他の人が完了するまで待つ必要があります。

makeGetCall(URLstring: "api1") 

背景に設定してください

makeGetCall(URLstring: "api3") 

を完了し、5秒ごとにトリガする

makeGetCall(URLstring: "api2") 

待機を完了するために待機。

func makeGetCall(URLstring: String, update: Bool) { 

    let completeURL = "http://myapi/" + URLstring 


    // Set up the URL request 
    guard let url = URL(string: completeURL) else { 
     print("Error: cannot create URL") 
     return 
    } 
    let urlRequest = URLRequest(url: url) 

    // set up the session 
    let config = URLSessionConfiguration.default 
    let session = URLSession(configuration: config) 

    // make the request 
    let task = session.dataTask(with: urlRequest) { 
     (data, response, error) in 
     // check for any errors 
     guard error == nil else { 
      print("error calling GET on /todos/1") 
      print(error as Any) 
      return 
     } 
     // make sure we got data 
     guard let responseData = data else { 
      print("Error: did not receive data") 
      return 
     } 

      // parse the result as XML 
     if URLstring == "devicelist.cgi" { 
      self.readDevice(XMLData: responseData) 
     } 

     if URLstring == "statelist.cgi" { 
      self.readDeviceData(XMLData: responseData, update: update) 
     } 

     if URLstring == "functionlist.cgi" { 
      self.readGewerke(XMLData: responseData) 
     } 
    } 

    task.resume() 

} 

誰かが助けてください。

ハーゲン

これは私が完了ハンドラを試みたものです:私は一緒に3つの通話を置く場合

override func viewDidLoad() { 
    super.viewDidLoad() 

    makeGetCall(input: "statelist.cgi") { 
     (result: Bool) in 
     print("finished statelist") 

    } 
    makeGetCall(input: "devicelist.cgi") { 
     (result: Bool) in 
     print("finished devicelist") 
    } 


    makeGetCall(input: "functionlist.cgi") { 
     (result: Bool) in 
     print("finished functionlist") 
    } 

} 

func makeGetCall(input: String, completion: @escaping (_ result: Bool) -> Void) { 



    let completeURL = "http://192.168.0.25/addons/xmlapi/" + input 


    // Set up the URL request 
    guard let url = URL(string: completeURL) else { 
     print("Error: cannot create URL") 
     return 
    } 
    let urlRequest = URLRequest(url: url) 

    // set up the session 
    let config = URLSessionConfiguration.default 
    let session = URLSession(configuration: config) 

    // make the request 
    let task = session.dataTask(with: urlRequest) { 
     (data, response, error) in 
     // check for any errors 
     guard error == nil else { 
      print("error calling GET on /todos/1") 
      print(error as Any) 
      return 
     } 
     // make sure we got data 
     guard data != nil else { 
      print("Error: did not receive data") 
      return 
     } 
     completion(true) 

    } 

    task.resume() 


} 

それはそれが必要として働いていました。 、それはまた、GCDで動作するはずですが、SWIFT 2.

makeGetCall(input: "devicelist.cgi") { 
     (result: Bool) in 
     print("finished devicelist") 
     self.makeGetCall(input: "functionlist.cgi") { 
      (result: Bool) in 
      print("finished functionlist") 
      self.makeGetCall(input: "statelist.cgi") { 
       (result: Bool) in 
       print("finished statelist") 

      } 
     } 
    } 

のための例のほとんどは、たぶん今誰かを助けることができる私の事。

おかげハーゲン

+0

完了ハンドラを 'makeGetCall()'に追加し、 'DispatchGroup'を使用して待機または通知します。 – shallowThought

+0

私は私の問題を解決しようとしましたが、うまくいきませんでした。誰かが私に助言を与えることができますか? – Hagen

+0

完了ハンドラで試したことを表示 – shallowThought

答えて

1

は、何かが起こったときに通知を受けるためにDispatchGroupを使用してください。

override func viewDidLoad() { 
    super.viewDidLoad() 

    let stateListGroup = DispatchGroup() 

    stateListGroup.enter() 
    makeGetCall(input: "statelist.cgi") { 
     (result: Bool) in 
     print("finished statelist") 
     stateListGroup.leave() 
    } 

    let deviceListGroup = DispatchGroup() 
    deviceListGroup.enter() 

    // the notify closure is called when the (stateList-) groups enter and leave counts are balanced. 
    stateListGroup.notify(queue: DispatchQueue.main) { 
     self.makeGetCall(input: "devicelist.cgi") { 
      (result: Bool) in 
      print("finished devicelist") 
      deviceListGroup.leave() 
     } 
    } 

    let functionListGroup = DispatchGroup() 
    functionListGroup.enter() 

    deviceListGroup.notify(queue: DispatchQueue.main) { 
     self.makeGetCall(input: "functionList") { 
      (result: Bool) in 
      print("finished functionlist") 
      functionListGroup.leave() 
     } 
    } 

    functionListGroup.notify(queue: DispatchQueue.main) { 
     print("update ui here") 
    } 
} 

プリント:

statelist.cgi 
finished statelist 
devicelist.cgi 
finished devicelist 
functionList 
finished functionlist 
update ui here 

session.dataTask()完了ハンドラは、バックグラウンドキューに呼び出されたことを覚えておいてください、私は予期しない動作を回避するために、メインキューにcompletion(true)を派遣することをお勧めします:

DispatchQueue.main.async { 
    completion(true) 
} 
+0

ありがとうたくさんのshallowThought。私はそれをgroup.notify(queue:DispatchQueue.main)に変更しました。 – Hagen

+0

ああ、申し訳ありません。地下鉄に書いてあります...答えの更新でそれを修正しました。ここで私たちはアップ投票/答えを受け入れることに感謝します。 – shallowThought

関連する問題