Как ждать завершения асинхронных звонков
Я выполняю три вызова API, используя Spotify API, чтобы получить следующие данные и сохранить их в моем Artist
объект:
- Исполнитель.
- Альбомы этого художника.
- Треки каждого альбома исполнителя.
Когда они будут готовы, я бы хотел передать объект другому контроллеру представления. Это выглядит примерно так: (Если бы выложил все 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.
Затем отобразите информацию о запросе (я полагаю, вы храните ее в БД для кеширования).