【问题标题】:Retrieving records on a Reference List (hierarchical records) - Swift Concurrency & CloudKit检索参考列表上的记录(分层记录) - Swift Concurrency & CloudKit
【发布时间】:2022-01-26 17:39:03
【问题描述】:

我正在使用 CloudKit(默认的公共数据库)来存储两支球队之间的比赛信息。我正在尝试使用带有 async/await 的 Swift Concurrent 方法来检索比赛和团队数据。

比赛被存储为带有一些元数据的“Match”RecordType,比如比赛进行的年份(“matchYear”)。 “比赛”记录类型还包含一个名为“团队”的记录类型的参考列表(每场比赛两个团队)。团队名称存储在“团队”记录类型(字段“团队名称”)中

我的 CloudKit 架构的粗略描述

“Match” Record Type
Fields:
   matchYear: Int64
   teams: Reference (List)
   …

“Team” Record Type
Fields:
   teamName: String
   …

通过以下代码,我可以从 CloudKit 读取所有“匹配”记录并将该列表存储到 MatchRecords 数组中,然后我可以使用它来显示匹配列表(使用 SwiftUI,如果这有什么不同的话)。结果数组还包含对每场比赛的球队的引用。

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
    }

如何检索作为此异步功能的一部分的团队记录,以便我还可以获取可用于列表视图的团队名称?

(我可能首先获取匹配列表,然后遍历该数组并检索每个匹配的详细数据,但这似乎很浪费。我猜应该有一种方法可以将它插入到标记为的 compactMap 闭包中上面的代码示例,但是我的 map/reduce 和 async/await 技能让我失望了……)

数据结构可能如下所述。

struct MatchRecord {
    var recordID: CKRecord.ID
    var matchYear: Int
    var teams: [TeamRecord]
    …
}

struct TeamRecord {
    var recordID: CKRecord.ID
    var teamName: String
    …
}

FWIW 我知道由于每场比赛只有两支球队,我也可以将球队名称存储为比赛记录的一部分,但我计划在未来还包括每支球队的名单信息,所以我需要想出一个干净且可扩展的方法来从 CloudKit 中检索这种类型的分层数据……

此处不能选择将 CoreData 与 CloudKit 一起使用。

【问题讨论】:

    标签: swift async-await cloudkit swift-concurrency


    【解决方案1】:

    经过一番思考,我想出了一个使用异步属性的有点难看的解决方案。 Match 和 Team 结构体定义大致是这些

    struct MatchRecord {
        var recordID: CKRecord.ID
        var matchYear: Int
        var teams: [TeamRecord]
        …
    }
    struct TeamRecord {
        var referenceID: CKRecord.Reference
        var name: String {
            get async {
                try! await CKContainer.default().publicCloudDatabase.record(for: referenceID.recordID)["teamName"] as! String
            }
        }
    }
    

    compactMap 在其中变得很小的 for 循环以填充团队结构(仅存储 ID,因为名称仅在以后检索)

                .compactMap {
                    let match = MatchRecord(
                        recordID: $0.recordID,
                        matchYear: $0[“matchYear"] as! Int,
                        teams: [])
                    for item in ($0["teams"] as! [CKRecord.Reference]) {
                        match.teams.append(TeamRecord(referenceID: item))
                    }
                    return match
                }
    

    当显示列表时,列表行在单独的视图中定义,其中异步属性是使用任务拉入的。沿着这条线

    struct MatchRow: View {
    ...
        @State var team0: String = ""
        @State var team1: String = ""
    
        var body: some View {
    ...
            Text(verbatim: "\(match.matchYear): \(team0) - \(team2)")
                .task{
                    guard team0.isEmpty else { return }
                
                    let (team0Result, team1Result) = await (match.teams[0].name, match.teams[1].name)
                    team0 = team0Result
                    team1 = team1Result
                }
            }
        }
    }
    

    我相信有一个更优雅的解决方案。我特别不喜欢在列表行视图中添加任务的想法,因为这会在很多地方分割逻辑......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多