CloudKit, Episode 6: Fetch Records | raywenderlich.com

With your query object ready to go, you’ll need to use a CloudKit database to perform it.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/27184225-cloudkit/lessons/6

In this episode you use a withThrowingTaskGroup but the usage seems odd to me. You haven’t actually performed your async task in the addTask method, so I’m not sure what the value was there. I understand the need for the task group itself, but you’ve not taken advantage of the functionality of the parallel tasks. Seem like it should be something more like this:

return try await withThrowingTaskGroup(of: Establishment?.self) { group in
    records.forEach { record in
        group.addTask { 
            try? await Establishment(record: record, database: database)
        }
    }

    return try await group
        .compactMap { $0 }
        .reduce(into: []) { $0.append($1) }
}
1 Like

Me neither. It was months ago that I recorded this, and I don’t remember what I was thinking. Apologies to all viewers; we’ll improve this in the next course update.

At this point, I’ve found there to be quite a lot of common generic async operations lacking in the standard library—in this case, a compactMap overload that does what your code does (and preserves order, as that’s generally desired). I might rewrite it this way:

establishments = try await database.records(matching: query).matchResults
  .compactMap { try await Establishment(record: $1.get(), database: database) }
public extension Sequence {
  func map<Transformed>(
    priority: TaskPriority? = nil,
    _ transform: @escaping (Element) async throws -> Transformed
  ) async rethrows -> [Transformed] {
    try await withThrowingTaskGroup(
      of: EnumeratedSequence<[Transformed]>.Element.self
    ) { group in
      for (offset, element) in enumerated() {
        group.addTask(priority: priority) {
          (offset, try await transform(element))
        }
      }
      
      return try await group.reduce(
        into: map { _ in nil } as [Transformed?]
      ) {
        $0[$1.offset] = $1.element
      } as! [Transformed]
    }
  }
  
  func compactMap<Transformed>(
    priority: TaskPriority? = nil,
    _ transform: @escaping (Element) async throws -> Transformed?
  ) async rethrows -> [Transformed] {
    try await map(transform).compactMap { $0 }
  }
}