0

サーバーからテキストファイルを取得し、テキストから特定の文字列を取得し、その文字列(URL)を使用してサーバーから音楽ファイルを取得するメソッド(getAndPlaySong)を持つクラスがあります。テキストファイルを取得するための最初のサーバー呼び出しは高速なので、同期的に実装しました。2つ目は時間がかかるので、表示を更新したいのですが。

メソッドが非同期リクエストの終了を待ってから続行するようにしたい。connectionDidFinishLoadingメソッドにBOOLを入れてみました:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"Succeeded! Received %d bytes of data",[_receivedData length]);
    [AppDelegate playAudioWithData: _receivedData];
    _dataIsReceived = YES; //BOOL

    // release the connection, and the data object
    [connection release];
    [_receivedData release];
}

次に、getAndPlaySongメソッドにwhileループを配置します。

[self startRequest: correctSongURL]; starts the request asynchronously

while (!_dataIsReceived) {
    //do stuff
}

その結果、アプリはループに達するとハングします。ループが終了することはなく、「Succeeded...」の出力も得られません。私は少し混乱していて、いくつかの入力に感謝します。

4

3 に答える 3

2

失礼に聞こえたくはありませんが、あなたがしたことは最悪のことです。もちろん、アプリは無限ループになっているためハングします。ループが最終的に終了したとしても、ループ内でアプリがスタックしている場合、ループの途中でユーザーがアプリで何かをしようとするとどうなりますか?考え方を変えて、ステートマシンでイベント駆動型プログラミングを使用する方法を学ぶ必要があります。これがiOSのパラダイムです。ナックルダウンして、読書や学習を行い、プログラムの考え方や構築方法を変える必要があります。

リクエストを行った後は何もしません。つまり、コードスニペットの次に来るコードはありません。代わりに、アプリは接続が終了するのを待って何もしません(ただし応答します)(アプリが何もしていない間、OSはユーザーに代わってスレッドを作成し、接続コードが終了すると、その中で接続コードが実行されます)終了したコードの残りの部分に通知する必要があります。たとえば、デリゲートを介して、または通知を介してこれを行うことができます)。

そして、それだけが座って待つ必要があるわけではありません-ユーザーが画面をタップした場合はどうなりますか?ユーザーがアプリを終了した場合はどうなりますか?もし...あなたのアプリがすべての可能なイベントに応答し、迅速に応答できる必要がある場合、接続はそれがリッスンして応答しなければならないもう1つのイベントです。ループしている場合はそれを行うことはできません。

このような場所ではループを使用しないでください。

「非同期リクエストが終了するのを待ってから続行するようにしたいのです。」いいえ、できません。GUIを使用するアプリケーションでは、このようなことはできません。関数は実行を終了する必要があります。ステートマシンを実装する必要があります。すべてのiOSはステートマシンであり、アプリケーションデリゲートがステートマシンを駆動する主なものです。次に、プログラムにイベントが追加されるにつれて、状態と状態間の遷移を追加します。

アプリがフォアグラウンドまたはバックグラウンドに入ったこと、またはメモリ不足の状況などがあることをコードに伝えるアプリデリゲートとそのメソッドを見てください。これはイベント駆動型プログラミングであり、考慮に入れるためにその原則を拡張して構築する必要があります接続イベントおよびその他のイベント。

少し耳障りに聞こえたらごめんなさい。

于 2012-05-26T04:56:45.267 に答える
1

アプリは無限であるため、ループにぶら下がっています。

iOSでは、NSURLConnectionDelegateは、接続でデータを受信したときにコールバックを取得し、データが受信されたときに通知を受ける方法です。そして、すべては非同期で、デリゲートを介して実行する必要があります。それがiOSで行われる方法です。

ストリーミングされる結果は、didRecieveDataメソッドのNSDataオブジェクトに保存する必要があります。

NSURLConnectionDelegateのドキュメントを見てください。ただし、ここに概要の例を示します。

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
     int statusCode = [(NSHTTPURLResponse *)response statusCode];    
     if(statusCode == 404) {
         // Post notification and let concerned parties know something went wrong.
         [self cleanupConnection];
     }
     else if( statusCode == 200) {
         // Success do something with the data.
         requestData = [[NSMutableData alloc] init];
     }
     else {
         [self cleanupConnection];
     }
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [requestData appendData:data];
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self finishedLoadingAppData];
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"Connection Attempt Failed with Error:%@", [error localizedDescription]);
}
于 2012-05-25T23:57:31.523 に答える
0

2つの簡単なオプションが思い浮かびます。完了した接続を処理するために呼び出すメソッドを作成するNSNotificationAPIを使用して、ロードが完了したときに通知を送信します

さらに、NSURLConnection didReceiveDataのメソッドを使用して、サーバーから段階的に送信されるデータを処理できます。

于 2012-05-25T22:12:01.267 に答える