【问题标题】:How to wait for async calls to finish如何等待异步调用完成
【发布时间】:2016-03-12 22:47:38
【问题描述】:

我正在使用 Spotify API 运行三个 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
}

【问题讨论】:

  • 如果你想按顺序调用异步函数 -- 即调用#1,等到完成然后检索结果,调用#2(可能有结果#1作为参数),等到完成,获取结果#2,等等 - 你必须有一个完成处理程序或其他方式来通知调用者异步函数完成。 SO上已经有很多这样的问题和很好的答案了。
  • 您的问题可能还包含一些特殊的“子问题:有一个 N 输入数组(例如 URL)得到一个 N个对象,获取每个对象都需要调用一个异步函数,这个问题也有解决方案,在SO上已经回答了很多次了。

标签: ios objective-c swift nsurlsessiondatatask


【解决方案1】:

NSURLSession(或NSURLSessionDataTask)的回调函数/块(或苹果术语中的完成处理程序)中,针对当前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.
}

这只是一种解决方案。一旦你有了想法,有很多方法可以实现你想要的。

【讨论】:

  • 对不起,语法是什么? [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error != nil) { NSLog(@"发生错误:%@", error.localizedDescription );返回; }
  • 我想我没有提到这是我在 swift 中做的一个项目,现在我在目标 c 中做。但我两次都遇到了同样的问题。 @蔡志伟
【解决方案2】:

2.5 年后回到这个话题。我正在寻找的是完成语法,但当时我不知道那是什么或如何寻求帮助。

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

希望这可以帮助遇到此问题的任何人。

【讨论】:

    【解决方案3】:

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

    无论哪种方式,我建议你在Activity类里面写AsyncTask类,然后你可以使用一个计数器等待三个调用完成,然后在onPostExecute()方法上你可以构建一个Parcelable对象并传递它在bundle(intent.putExtra(authorObject))的第二个Activity的onCreate方法中接收。

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

    【讨论】:

    • 问题标记为 iOS 和 Swift,而不是 Android 或 Java
    猜你喜欢
    • 1970-01-01
    • 2011-10-04
    • 1970-01-01
    • 2021-11-13
    • 2014-04-03
    相关资源
    最近更新 更多