I am using CloudKit (the default public database) to store information about matches between two teams. I am trying to use the Swift Concurrent approach with async/await to retrieve the match and team data.
The matches are stored as “Match” RecordType with some metadata, like the year the match was played (“matchYear”). The “Match” Record Type also contains a Reference List to a RecordType called “Team” (two teams for each match). The team names are stored in the “Team” Record Type (field “teamName”)
Rough description of my CloudKit Schema
“Match” Record Type
Fields:
matchYear: Int64
teams: Reference (List)
…
“Team” Record Type
Fields:
teamName: String
…
With the following code I am able to read all “Match” records from the CloudKit and store that list to an array of MatchRecords, which I can then use to display a list of matches (using SwiftUI, if that makes any difference). The resulting array also contains references to the teams for each match.
struct MatchRecord {
var recordID: CKRecord.ID
var matchYear: Int
var teams: [CKRecord.Reference]
…
}
…
private lazy var container = CKContainer.default()
private lazy var database = container.publicCloudDatabase
…
@MainActor func loadMatchList() async throws -> [MatchRecord] {
let predicate = NSPredicate(value: true)
let sortDescriptors = [NSSortDescriptor(key: “matchYear", ascending: false),NSSortDescriptor(key: "___createTime", ascending: false)]
let query = CKQuery(recordType: “Match”, predicate: predicate)
query.sortDescriptors = sortDescriptors
let (matchResults, _) = try await database.records(matching: query)
let allMatches: [MatchRecord] = matchResults
.compactMap { _, result in try? result.get() }
.compactMap {
let match = MatchRecord(
recordID: $0.recordID,
matchYear: $0[“matchYear"] as! Int,
teams: $0["teams"] as! [CKRecord.Reference])
// Potentially team record retrieval goes here…
return match
}
return allMatches
}
How do I retrieve the Team records as part of this async function so that I will have also the names of the teams available for the list view?
(I could potentially first fetch the list of matches and then loop through that array and retrieve the detail data for each match but that seems wasteful. I am guessing there should be a way to insert this in the compactMap closure marked down in the code sample above, but my map/reduce and async/await skills fail me…)
The data structure could be something along as described below.
struct MatchRecord {
var recordID: CKRecord.ID
var matchYear: Int
var teams: [TeamRecord]
…
}
struct TeamRecord {
var recordID: CKRecord.ID
var teamName: String
…
}
FWIW I know that as there are only two teams for each game, I could also store the team names as part of the Match record, but In the future I am planning to also include the roster information for each team, so I need to come up with a clean and scalable method to retrieve this type of hierarchical data from CloudKit…
Using CoreData with CloudKit is not an option here.