Как ждать завершения асинхронных звонков

Я выполняю три вызова API, используя Spotify API, чтобы получить следующие данные и сохранить их в моем Artist объект:

  1. Исполнитель.
  2. Альбомы этого художника.
  3. Треки каждого альбома исполнителя.

Когда они будут готовы, я бы хотел передать объект другому контроллеру представления. Это выглядит примерно так: (Если бы выложил все NSURLSession код там при необходимости)

func getArtist(artistName) {
 getAlbums(artistIdString)}

func getAlbums(artistIdString) {
 a = Album
 Artist.albumsArray.append(a)
 for album in Artist.albumsArray {
 getTracks(albumIdString) 
 }
}

func getTracks (albumIdString) {
 t = Track
 for album in Artist.albumsArray {
  if idString == albumIdString {
  album.append(t)
  }
 }
}

func passArtist {  
 DataStore.sharedInstance().Artist = Artist
}

3 ответа

Решение

В функции / блоке обратного вызова (или обработчик завершения в терминах Apple) NSURLSession (или же NSURLSessionDataTask), запустите функцию проверки текущего Artist объекта и посмотреть, все ли 3 обязательные элементы были там (и если да, позвоните passArtist).

Независимо от того, каким будет конечный заказ, он в конечном итоге вызовет passArtist как только это будет сделано, выборка 3 элементов, если вы это сделали.

Вот простой пример, демонстрирующий идею в Objective-C (как было запрошено OP):

- (void)getArtistDataWithRequest:(NSURLRequest *)request
{
    NSURLSession         *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task    = [session dataTaskWithRequest:request
                                               completionHandler:^(NSData        *data,
                                                                   NSURLResponse *response,
                                                                   NSError       *error)
                                     {
                                         if (error)
                                         {
                                             // Something went wrong, fallback.
                                             NSLog(@"An error occurred: %@", error.localizedDescription);

                                             // You could use some error handler e.g.:
                                             // [self connectionDidFailWithError:error];

                                             return;
                                         }
                                         else if (response)
                                         {
                                             // Seems working, moving forward.
                                             [self connectionDidReceiveSpotifyServerResponse:response
                                                                                     andData:data];
                                         }

                                     }];
    [task resume];
}

- (void)connectionDidReceiveSpotifyServerResponse:(NSURLResponse *)aResponse
                                          andData:(NSData *)aResponseData
{
    // Do what you want here with the data you get, either it's album, track,
    // or whatever.

    // Assuming your "Artist" property is named "myArtist", and the "Artist"
    // class has a method to process the data you get from Spotify API:
    [_myArtist handleArtistData:aResponseData];

    // Now check your Artist object's element with another method. e.g.:
    if ([_myArtist isLoadingComplete])
    {
        // Done loading the object, pass it to view controller.
    }

    // Not yet done, do nothing for now.
}

Это только одно решение. Есть много способов добиться того, чего вы хотели, когда у вас появилась идея.

Возвращаясь к этому 2,5 года спустя. То, что я искал, было синтаксисом завершения, хотя в то время я не знал, что это было или как попросить помощи с ним.

func getArtist(artistName: String, completion: (Artist) -> ()) {
     getAlbums(artistIdString)
}

Надеюсь, это поможет любому, кто сталкивался с этим.

Во-первых, как вы делаете три вызова API одновременно? Или пользователь сначала выбирает исполнителя, затем вы звоните, чтобы получить альбомы, затем отображаете альбомы, затем пользователь выбирает альбом, и вы делаете третий запрос?

В любом случае, я предлагаю вам написать класс AsyncTask внутри класса Activity, затем вы можете использовать счетчик, чтобы дождаться завершения трех вызовов, затем в методе onPostExecute() вы можете построить объект Parcelable и передать его в комплекте. (intent.putExtra(authorObject), чтобы получить его в методе onCreate второго Activity.

Затем отобразите информацию о запросе (я полагаю, вы храните ее в БД для кеширования).

Другие вопросы по тегам