Понимание результата выборки CKRecords с новым API async/await
Я немного запутался в том, как работать со сложными типами данных 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>>. или список пар ключ / значение, в котором CKRecord.ID является ключом для значения Result<CKRecord, Error>.
Это довольно сбивает с толку .. Итак, если я правильно понимаю, то:
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>
Я просто считаю, что не совсем понимаю, как правильно получить доступ к CKRecord из чего-то, что представлено:
Dictionary<CKRecord.ID, Result<CKRecord, Error>>.Element
структура данных.
Мы очень ценим любое понимание.
Спасибо
Обновлять
Хорошо, на основе ответа от @Shadowrun, если я правильно понимаю:
Результат от:
let result = try await container.privateCloudDatabase.records(matching: query)
является кортежным типом. Это означает, что он состоит из двух элементов: первый - это словарь данных, а второй - это queryCursor.
Если я хочу перебрать часть словаря кортежа и получить CKRecord:
for rec in result.0 {
self.myCKRecordArray.append(try rec.value.get())
}
Это не дает мне никаких ошибок .. Правильно ли я это понимаю?
2-е обновление работает так, как ожидалось.
2 ответа
Существует эквивалентность между функциями, возвращающими
Result<T, E>
и функции, которые либо возвращают
T
или бросить
E
. И аналогичная эквивалентность для функций, возвращающих кортеж из
(T?, E?)
При отображении функций с обработчиками завершения на асинхронные функции они становятся функциями бросания
let (result, err) = try await container….
Должно быть просто
let result = ...
, выдается ошибка, если таковая имеется
Рискуя проявить педантичность, могу я предложить прочитать документацию?
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
. Это имеет то преимущество, что он либо возвращает значение, либо выбрасывает, и вы можете хорошо с этим справиться.