2016-08-18 7 views
1

最近、自分でTelegram Bot APIを書き込もうとしました。しかし、このプロジェクトは、URLSession(以前のNSURLSession)の問題でレンガの壁に当たったようです。次のようにURLSessionから受信したデータを取得する方法を教えてください。

コール構造は次のとおりです。

理想的

getMe() -> getData() -> NSURLSession

、私は、プロセスへの適用のために戻っgetMe()に渡さNSURLSessionから返されたデータを持っていると思います。しかし、これは私が試した方法では可能ではありませんでした。

以下は私が使用しているコードです。 synthesiseURL()は、Telegram Bot APIでアクションを実行するために、アプリケーションがセッションを開くURLを生成します。 synthesiseURL()によって生成されたURLのテンプレートはhttps://api.telegram.org/bot\(token)/\(tgMethod)です。

// NSURLSession getData: gets data from Telegram Bot API 
func getData(tgMethod: String, arguments: [String] = [String](), caller: String = #function) { 
    let url = synthesiseURL(tgMethod: "getMe"), request = NSMutableURLRequest(url: url) 

    var receivedData = String() 

    let session = URLSession.shared.dataTask(with: request as URLRequest) { data, response, err in 

     if err != nil {print(err!.localizedDescription); return} 

     DispatchQueue.main.async { 
      receivedData = String(data: data!, encoding: String.Encoding.nonLossyASCII)! 
      print(receivedData) 
     } 
    } 

    session.resume() 
} 

私は戻っ機能getMeに、ボットAPIの応答が含まれているreceivedDataを、渡すためにgetDataを取得しようとしてきました。

func getMe() -> String { 
    HTTPInterface(botToken: token).get(tgMethod: "getMe") 
    return [???] // here's where the data from getData() should come 
} 

私はメインスレッドに完了ハンドラ、コールバック、非同期呼び出しなどを試してみましたが、予想通り、いずれも(空の文字列を返しますgetMe())働いているように見えません。

なぜそうであり、修正できますか?

答えて

1

基本的な問題は、getMe()関数が即時の戻り値型を持つと宣言されていますが、その文字列を取得する遅延/非同期呼び出しに依存します。タイムラインは、このようなものになります。

  1. getMe()いくつかのクライアントコードによって呼び出されると、データ実行の次の行へ
  2. getMe()動きを得るためにURLSessionを起動し、返すメソッドの
  3. getMe()キック文字列(この時点ではまだ空です)。 getMe()機能は今戻ってきたし、クライアントのコードの実行は、データとURLSession完了は
  4. String結果を進め続けているが、実行は非常にデータがどこにでも

慣れていない、すでに上に移動しましたそれほど簡単な修正プログラムは、技術李を使用することです

func getMe(callback:String->()) { 
    //getData and pass a closure that executes the callback closure with the String data that comes back 
} 

:最も簡単な修正はURLSessionデータが戻って来るとき、あなたのgetMe機能は、のようなものを戻り値の型を持っているだけでなく、クロージャパラメータにコールバックしないようにすることですURLセッションのデータが返されるまでgetMe()が結果を返さないようにセマフォをディスパッチします。しかし、このようなアプローチはあなたの主なスレッドを失速させる可能性があり、正しい選択である可能性は低いです。

+0

あなたの答えをありがとう!あなたが提案した閉鎖に関して、私はこのデータをどのようにしてメインスレッド上で処理すべきですか? 'getMe()'が返り値として使うために 'getMe()'にデータを渡すことは可能でしょうか? – perhapsmaybeharry

+0

@perhapsmaybeharry 'getMe()'関数の中でディスパッチセマフォのようなものを使うと、 'getMe()'がURLSessionからの応答を得るまで実行を一時停止し、その答えを戻り値として使うことができます。しかし、これは主なスレッドをブロックし、応答が返ってくるまでUIをフリーズする可能性があります(悪い考え方)。最善の方法は、 'getMe()'を呼び出すコードがクロージャー内を通過するようにすることです。これは、 'getMe()'が非同期的に完了したときにString結果で実行されるべきで、 'getMe()関数。私は見る。 –

+0

その意味で、私は非同期補完ハンドラを使うつもりだと思います。ご協力いただきありがとうございます! – perhapsmaybeharry

関連する問題