我是第一次使用 CloudKit,在执行 CKQueryOperation 来查询给定类型的所有记录时遇到问题。苹果已经弃用了我在网上找到的大部分内容,而且除了 func 声明之外,他们关于这些内容的文档完全是空白的,这无济于事。我认为我已经完成了代码的“骨架”,但不确定 .recordMatchedBlock
和 .queryResultsBlock
中的内容。
我有一个 func queryAllNotes() ,它应该查询公共(public)数据库中类型为“Notes”的所有记录,并返回注释标题及其关联的 cloudID 的元组数组,这只是在它执行操作时为其提供的唯一 recordName已添加到数据库中。
这是 queryAllNotes() 的代码:
private func queryAllNotes() -> [(title: String, cloudID: String)] {
/*
query all notes in the cloud DB into an array to populate
the tableView
*/
var resultArray: [(title: String, cloudID: String)] = []
//set the cloud database to .publicCloudDatabase
let container = CKContainer.default()
let cloudDB = container.publicCloudDatabase
let pred = NSPredicate(value: true) //true -> return all records
let query = CKQuery(recordType: "Notes", predicate: pred)
let queryOperation = CKQueryOperation(query: query)
queryOperation.database = cloudDB
queryOperation.resultsLimit = 100
queryOperation.recordMatchedBlock = { (record: CKRecord) in
let noteTitle = record["Title"] as! String
let noteCloudID = record.recordID.recordName
resultArray.append((noteTitle, noteCloudID))
}
queryOperation.queryResultBlock = { (cursor, error) in
}
return resultArray
}
据我了解,查询返回的每条记录都会调用.recordMatchedBlock
,因此我认为它是完整的,但我可能是非常错误的。关于 .queryResultBlock
,我的理解是,从技术上讲,查询一次仅返回一条记录,而该 block 基本上告诉查询再次运行 中所有记录的下一条记录。 .resultLimit
。我该如何构建这个查询?我很想了解每个 block 的作用。
这也适用于 macOS 应用程序;我不知道 macOS 与 iOS 的代码是否不同,但我认为我应该包含此代码以防万一。
此外,我收到一条错误消息,提示“表达式类型在没有更多上下文的情况下不明确”,我认为这是因为我尚未完成查询设置。如果是出于不同的原因也可以解释为什么会发生这种情况。
编辑
我在 viewDidLoad()
内部调用这个函数,如下所示:
//array var for the array that is used to populate the tableView
var noteRecords: [(title: String, cloudID: String)] = []
override func viewDidLoad() {
super.viewDidLoad()
// do additional setup here
// set serachField delegate
searchField.delegate = self
// set tableView delegate and data source
tableView.delegate = self
tableView.dataSource = self
// load all NoteRecords in public cloud db into noteRecords
noteRecords = queryAllNotes()
}
最佳答案
使用新的async
模式,从CloudKit获取数据变得更加容易。
您可以直接调用records(matching:resultsLimit:)
,而不是CKQueryOperation
,并将结果映射到您喜欢的任何内容。
将可能的错误交给调用者。
func queryAllNotes() async throws -> [(title: String, cloudID: String)] {
//set the cloud database to .publicCloudDatabase
let container = CKContainer.default()
let cloudDB = container.publicCloudDatabase
let pred = NSPredicate(value: true) //true -> return all records
let query = CKQuery(recordType: "Notes", predicate: pred)
let (notesResults, _) = try await cloudDB.records(matching: query,
resultsLimit: 100)
return notesResults
.compactMap { _, result in
guard let record = try? result.get(),
let noteTitle = record["Title"] as? String else { return nil }
return (title: noteTitle, cloudID: record.recordID.recordName)
}
}
并使用它
override func viewDidLoad() {
super.viewDidLoad()
// do additional setup here
// set serachField delegate
searchField.delegate = self
// set tableView delegate and data source
tableView.delegate = self
tableView.dataSource = self
// load all NoteRecords in public cloud db into noteRecords
Task {
do {
noteRecords = try await queryAllNotes()
tableView.reloadData()
} catch {
print(error)
}
}
}
请观看 WWDC 2021 的相关视频,了解有关 async
CloudKit API 以及 Apple examples on GitHub 的详细信息。 .
旁注:
使用结构而不是元组。不鼓励使用元组作为数据源数组。
关于swift - 了解如何正确执行 CKQueryOperation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71529092/