【问题标题】:Understanding result of fetching CKRecords with new async/await API了解使用新的 async/await API 获取 CKRecords 的结果
【发布时间】:2021-09-02 06:18:06
【问题描述】:

对于如何处理复杂的 Swift 数据类型、它们对变量的赋值以及访问其中的值,我有点困惑。希望有人可以澄清以下内容:

当尝试从 SwiftUI 和 CloudKit 获取数据,并尝试重写 CK 函数以符合 async/await 时,我有以下代码行:

let result = try await container.privateCloudDatabase.records(matching: query)

现在这一行应该从云私有数据库中获取与指定查询匹配的所有记录并返回一些CKRecords

旧函数是这样做的:

container.privateCloudDatabase.perform(query, inZoneWith: nil) { (rec, err) in 
    for record in rec {
        print("Found this record: \(record)")
    }
}

这很好用,因为 perform(_:inZoneWith:) 会返回一个 CKRecord 和一个错误,它们在 (rec, err) in 语句中被“挑选出来”并传递到循环中进行迭代。

使用新的 async/await 方法,我试图简单地等待并为找到的所有记录分配一个变量,然后迭代返回的数据,挑选出 CKRecords 并执行我想要的任何任务。

我感到困惑的是,当我试图从返回的结果中挑选出数据时,我会以多种方式得到错误。我不完全理解如何描述返回值的数据结构,我认为这是问题的根本原因。

我尝试了一些方法并收到以下错误消息:

如果我尝试:

let (result, err)  = try await container.privateCloudDatabase.records(matching: query)

当我使用(尝试将 CKRecords 附加到我之前创建的 CKRecords 数组中)时:

for record in result {
   self.myCKRecordArray.append(record)
}

错误信息具体说明:

Cannot convert value of type 'Dictionary<CKRecord.ID, Result<CKRecord, Error>>.Element' (aka '(key: CKRecord.ID, value: Result<CKRecord, Error>)') to expected argument type 'CKRecord'

这肯定给了我一些线索。我相信我的 result 变量包含 Dictionary>.Element 或键/值对列表,其中 CKRecord.ID 是 Result 的键价值。

这很令人困惑..所以如果我理解正确,那么:

        for thisDict in result {
            let (realResult, err) = result[thisDict.key]
            print("Found this record: \(realResult)")
        }

理论上应该把每个CKRecord的输出分配给realResult吧?我只是得到错误:Type of expression is ambiguous without more context

我尝试将其更改为 valueForKey 并为其提供更多上下文,但错误消息没有任何变化:

let (realResult, err) = result(valueForKey:thisDict.key) as Result<CKRecord, Error>

我只是认为我不完全理解如何从由 Dictionary&lt;CKRecord.ID, Result&lt;CKRecord, Error&gt;&gt;.Element 数据结构表示的东西正确访问 CKRecord。

非常感谢任何对理解的洞察力。

谢谢

更新

好的,根据@Shadowrun 的回答,如果我理解正确的话:

结果来自:

let result  = try await container.privateCloudDatabase.records(matching: query)

是一个元组类型。这意味着它有两个元素,第一个是数据字典,第二个是 queryCursor。

如果我想遍历元组的 Dictionary 部分并取出 CKRecord:

        for rec in result.0 {
            self.myCKRecordArray.append(try rec.value.get())
        }

这不会给我任何错误..我理解正确吗?

第二次更新 它确实以这种方式按预期工作。

【问题讨论】:

    标签: ios swift cloudkit ios15


    【解决方案1】:

    返回 Result&lt;T, E&gt; 的函数与返回 T 或抛出 E 的函数之间存在等价关系。以及返回元组(T?, E?)的函数的类似等价

    当将带有完成处理程序的函数映射到异步函数时,它们变成了抛出函数,所以应该是:

    let result = try await container….
    

    抛出错误(如果有)

    【讨论】:

    • 好的,有道理,谢谢,但是当尝试迭代该结果时,它是一种比 CKRecords 数组复杂得多的数据类型: For-in 循环需要 '(matchResults: [ CKRecord.ID : Result], queryCursor: CKQueryOperation.Cursor?)' 符合'Sequence'
    • 所以结果是一个元组类型,第一个元素是字典,你可以迭代它吗?不能在一个元组中。
    • 我已经在底部更新了我的问题,看看我是否理解你所说的正确。我的错误已经消失,我目前没有更新到 iOS 15 的实际设备进行测试来验证操作。我想我明白了..
    • 我能够测试并且它确实按预期工作。谢谢你的信息
    【解决方案2】:

    冒着迂腐的风险,我可以建议阅读文档吗?

    https://developer.apple.com/documentation/cloudkit/ckdatabase/3794332-records

    func records(matching query: CKQuery, 
        inZoneWith zoneID: CKRecordZone.ID? = nil, 
        desiredKeys: [CKRecord.FieldKey]? = nil, 
        resultsLimit: Int = CKQueryOperation.maximumResults) async throws -> 
            (matchResults: [CKRecord.ID : Result<CKRecord, Error>],     
              queryCursor: CKQueryOperation.Cursor?)
    

    所以你的结果是元组。致电您的结果tuple。那么tuple.matchResults 是一个以 ID 为键的字典,其值为 Result 对象。

    在我看来,从 Result 对象中提取值的最佳方法是使用 get。这样做的好处是它要么返回一个值,要么抛出,你可以很好地处理它。

    【讨论】:

      猜你喜欢
      • 2020-03-25
      • 1970-01-01
      • 2012-05-19
      • 2012-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-07
      • 2018-09-30
      相关资源
      最近更新 更多