如何等待异步调用完成

How to wait for async calls to finish

我正在 运行 三个 API 使用 Spotify API 调用,以便获取以下数据并将它们存储到我的Artist 对象:

  1. 艺术家。
  2. 那个艺术家的专辑。
  3. 艺术家每张专辑的曲目。

完成后,我想将对象传递给不同的视图控制器。它看起来像这样:(如果有必要的话 post 所有 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
}

首先,您如何同时进行三个 API 调用? 还是用户先选择艺术家,然后你调用获取专辑,然后显示专辑,然后用户选择专辑,你进行第三次请求?

无论哪种方式,我建议你把AsyncTask class写在Activityclass里面,然后你可以用一个计数器等待三个调用完成,然后on onPostExecute() 方法,您可以构建一个 Parcelable 对象并将其传递到包中(intent.putExtra(authorObject) 以在第二个 Activity.

的 onCreate 方法中接收它

然后显示请求的信息(我猜你是把它存储在数据库中进行缓存)

NSURLSession(或NSURLSessionDataTask)的回调function/block(或Apple术语中的完成处理程序)中,运行 针对当前 Artist 对象的检查函数,查看是否所有 3 个必需元素都存在(如果存在,调用 passArtist)。

无论完成顺序如何,如果您这样做,它最终会在完成获取 3 个元素后调用 passArtist

这里有一个简单的例子来证明 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)
}

希望这对遇到此问题的任何人有所帮助。