2016-09-26 7 views
0

Googleの場所APIを使用してAPIリクエストを行う機能があります。 API応答データから、私は値を取得し、それを変数に設定しようとします。この関数は別の関数の中で呼び出されます。私はその変数にアクセスしようとしましたが、残念ながら変数にはまだ値が入っていません。これはスレッドの問題のようですが、修正方法はわかりません。APIからスウィフトget threading issue

更新: 私はレスポンスに基づいてコードを更新しました。残念ながら私はまだAPIリクエストからの値で変数にアクセスすることができません。補完ハンドラを使用するapi要求を行う関数を書き直しました。 mapView(mapView:GMSMapView !, didTapInfoWindowOfMarkerマーカー:GMSMarker!)は、Googleマップフレームワークの関数です。完了ハンドラを使用するにはこれも書き直す必要がありますか?

//変数

var website = "" 

// API要求

func getWebsite2(id: String, completion: (result: String) -> Void) { 

    var url = NSURL(string: "https://maps.googleapis.com/maps/api/place/details/json?placeid=\(id)&key=AIzaSyAWV1BUFv_vcedYroVrY7DWYuIxcHaqrv0") 

    self.dataTask = defaultSession.dataTaskWithURL(url!) { 
     data, respnse, error in 
     let json : AnyObject 
     do { 
      json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) 
      var dictionArr = json["result"] 
      self.website = dictionArr!!["website"] as! String 
      print(self.website) 
     } 
     catch { 
      print(error) 

     } 
    } 
    self.dataTask?.resume() 
} 

//第二の機能

func mapView(mapView: GMSMapView!, didTapInfoWindowOfMarker marker: GMSMarker!) { 

    let storeMarker = marker as! PlaceMarker 

     self.getWebsite2(storeMarker.id!) { 
      (result: String) in 

      print("inside did tap") 
      print(self.website) 
      // problem still here 
      // above two lines of code never run 
    } 

    self.performSegueWithIdentifier("toWebView", sender: nil) 
} 

//有するコード私はこのようdefaultSessionとdataTaskを初期化します。

let defaultSession = NSURLSession(configuration:  NSURLSessionConfiguration.defaultSessionConfiguration()) 
var dataTask: NSURLSessionDataTask? 
+0

ネットワークリクエストは非同期なので、残りのコードはネットワークリクエストが完了する前に実行されています。 'defaultSession.dataTaskWithURL'が補完ブロックを渡すのと同じ方法で、完了ブロックを取るためにあなたの関数' getWebsite2'を書く必要があります。 –

+0

応答のためにあなたとOlegに感謝します。私は現在あなたとOlegの提案に従っており、補完ハンドラを使用しようとしています。私はそれを把握するとアップデートを投稿します – ray

+0

あなたのスニペットから 'defaultSession'がどのように初期化されるかははっきりしません。 'NSURLSession.shared()'へのローカル参照であると仮定すると、コードは別のスレッド上で実行され、データ競合が発生します。あなたは 'self.website = ...'を 'dispatch_async(dispatch_get_main_queue())' {}}クロージャでラップする必要があります。 – user2378197

答えて

1

getWebsite2関数に渡された完了ハンドラは呼び出されません。この(擬似)コードは、サーバから受け取った文字列を受け取り、didTapInfoWindowOfMarkerで呼び出されたクロージャに渡す方法を示しています。

func getWebsite2(id: String, completion: (result: String) -> Void) { 

    self.dataTask = defaultSession.dataTaskWithURL(url!) { 
    data, response, error in 

     // now on background thread 
     let someStringFromNetwork = data[0] 

     dispatch_async(dispatch_get_main_queue(),{ 
      completion(someStringFromNetwork) 
     }) 
    } 
} 
0

最初に変数のアンラッピングを強制しないでください。必要な場合は常にdo{} catch{}を使用してください。あなたはtryif let条件をどのように処理するかを示して

この小さなコードブロックは:

do { 
     let jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String:AnyObject] 
     if let dictionary = jsonObject["result"] as? [String: String] { 
      self.website = dictionary["website"] 
     } else { 
      print("Parse error") 
     }  
    } catch { 
     print("JSON error: \(error)") 
    } 

第二に defaultSession.dataTaskWithURL彼が終了しますときだけデータを設定します非同期要求です。

別の世界では、リクエストが完了していないときに値を印刷しようとします。 あなたの問題を解決するには、Completion Handlersを使用してください。