swift 了解使用新的async/await API获取CKRecords的结果

htrmnn0y  于 2023-06-21  发布在  Swift
关注(0)|答案(2)|浏览(129)

我对如何处理复杂的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和一个Error,它们在(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<CKRecord.ID,Result<CKRecord,Error>>.Element,或者一个键/值对列表,其中CKRecord.ID是Result<CKRecord,Error>值的键。
这是相当混乱。如果我理解正确的话,那么:

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

理论上应该导致分配给realResult的每个CKRecord的输出,对吗?我只是得到了错误:Type of expression is ambiguous without more context
我尝试将其更改为valueForKey并给予更多上下文,但错误消息没有更改:

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

我只是认为我不完全理解***如何***从由a表示的内容中正确访问CKRecord:Dictionary<CKRecord.ID, Result<CKRecord, Error>>.Element数据结构。
任何对理解的洞察都是非常赞赏的。
谢谢你

更新

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

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

是元组类型。这意味着它有两个元素,第一个是数据的Dictionary,第二个是queryCursor。
如果我想迭代元组的Dictionary部分并取出CKRecord:

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

这不会给予我任何错误。我理解的对吗?

***第二次更新***它确实按照预期的方式工作。

gojuced7

gojuced71#

返回Result<T, E>的函数与返回T或抛出E的函数之间存在等价性。返回(T?, E?)元组的函数的类似等价性
当将带有完成处理程序的函数Map到异步函数时,它们变成了抛出函数,所以应该是:

let result = try await container….

如果有错误,则会引发该错误

fquxozlt

fquxozlt2#

冒着迂腐的风险,我可以建议阅读文档吗?
https://developer.apple.com/documentation/cloudkit/ckdatabase/3856524-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。这样做的好处是,它要么返回一个值,要么抛出,您可以很好地科普这一点。

相关问题