4

I'm new to Swift, coming from JS, and I've started to build an iOS app.

Initially I went down the road, using Promise Kit for the async stuff, as it seemed easier to me than other things I read about.

Regardless, in JS, I use the following pattern a lot:

async function doAyncFunction(item) {
  try {
    // do async call to fetch data using item
    return Promise.resolve(data);
  } catch (error) {
    return Promise.reject(error);
  }
}
const promises = items.map((item) => doAyncFunction(item));
const results = await Promise.all(promises);

And I ultimately got this working with Promise Kit with something like this:

func doManyAsyncRequests(userIds: [String], accessToken: String) -> Promise<Void> {
  Promise { seal in
    let promises = spotifyUserIds.map {
      doSingleAsyncRequest(userId: $0.id, accessToken: accessToken) // this function returns a promise
    }
    when(fulfilled: promises).done { results in
      print("Results: \(results)")
      // process results
    }.catch { error in
      print("\(error)")
      // handle error
    }
  }
}

Promise Kit's when is similar to JavaScript's Promise.all() in that once the promises are fulfilled, things are triggered to move along in the code.

As my learning curve is slow enough, I've decided to start coding for iOS 15 and use Swift async/await.

QUESTION: What Swift async/await pattern that will do the above, similar to Promise Kit's wait and JavaScript's Promise.all()?

Thanks.

UPDATE: Thanks to @workingdog, who helped me arrive at the solution below. I now gotta work on error handling, but that's a different topic for now.

func getAllThings(users: [User], accessToken: String) async -> [Thing] {
    var allThings: [Thing] = []
    await withTaskGroup(of: [Thing].self) { group in
        for user in users {
            group.async {
                let userThings = await self.getUsersThings(
                    accessToken: accessToken,
                    displayName: user.displayName,
                    userId: user.id
                )
                return userThings
            }
        }
        for await (userThings) in group {
            allThings = allThings + userThings
        }
    }
    return allThings
}
4

1 回答 1

1

您可能正在寻找withTaskGroup(...),例如:

func getAll() async {
    await withTaskGroup(of: Void.self) { group in
        await getPosts()
        for post in posts {
            group.async { await self.getCommentsFor(post: post) }
        }
    }
}

我已经在 github 上设置了自己的基本测试来学习这一点:https ://github.com/workingDog/TestAsync

编辑:

这就是我将如何返回一系列带有他们评论的帖子。如您所见,它不如 getAll() 简洁。

func getAllPosts() async -> [Post] {
    // this is the tricky parameter bit, the tuple returned when you call group.async {...}
    await withTaskGroup(of: (Int, [Comment]).self) { group in
        // get all the posts
        var thePosts: [Post] = await fetchThem()
        // for each post get all the comments (concurrently)
        for post in thePosts {
            group.async {
                let comments: [Comment] = await self.fetchThem(with: post)
                return (post.id, comments)
            }
        }
        // add the comments to their corresponding post (concurrently)
        for await (postid, comnts) in group {
            if let ndx = thePosts.firstIndex(where: {$0.id == postid}) {
                thePosts[ndx].comments = comnts
            }
        }
        // when all done, return all post with their comments all cooked up
        return thePosts
    }
}
于 2021-07-14T00:08:38.753 回答