Search code examples
iosobjective-cswiftnsurlsessiondatatask

How to wait for async calls to finish


I am running three API calls using the Spotify API, in order to get the following data and store them into my Artist object:

  1. The artist.
  2. That artist's albums.
  3. Tracks of each albums of the artist.

Once they are done, I would like to pass the object to a different view controller. It looks something like this: (If could post all the NSURLSession code in there if necessary)

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
}

Solution

  • In the callback function/block (or completion handler in Apple's term) of NSURLSession (or NSURLSessionDataTask), run a check function against the current Artist object and see if all the 3 required elements were there (and if so, make a call to passArtist).

    No matter how the finishing order is, it will eventually call the passArtist once it's done fetching 3 elements if you did so.

    Here's a simple example to demonstrate the idea in Objective-C (as OP requested):

    - (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.
    }
    

    This is just one solution. There are many ways to achieve what you wanted once you get the idea.