了解如何正确执行 CKQueryOperation
Understanding how to correctly execute CKQueryOperation
我是第一次使用 CloudKit,在执行 CKQueryOperation 来查询给定类型的所有记录时遇到了问题。 Apple 已经弃用了我在网上找到的大部分内容,并且除了 func 声明之外,他们对这些内容的文档完全空白,这无济于事。我想我已经完成了代码的“骨架”,但不确定 .recordMatchedBlock
和 .queryResultsBlock
.
中包含什么
我有一个 func queryAllNotes(),它应该查询 public 数据库中类型为“Notes”的所有记录和 return 笔记标题及其关联的 cloudID 的元组数组,它只是添加到数据库时赋予它的唯一记录名称。
这是 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
}
根据我的理解,查询 return 的每条记录都会调用 .recordMatchedBlock
,所以我认为它是完整的,但我可能错了。关于 .queryResultBlock
,我的理解是技术上查询一次只能 return 一条记录,这个块基本上告诉查询再次 运行 以获取所有记录的下一条记录.resultLimit
。我该如何构造这个查询?我很想了解每个模块的作用。
这也是针对 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 获取数据变得更加容易。
而不是 CKQueryOperation
你直接调用 records(matching:resultsLimit:)
并将结果映射到你喜欢的任何东西。
一个可能的错误交给了调用者。
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.
的详细信息
旁注:
使用结构而不是元组。不鼓励使用元组作为数据源数组。
我是第一次使用 CloudKit,在执行 CKQueryOperation 来查询给定类型的所有记录时遇到了问题。 Apple 已经弃用了我在网上找到的大部分内容,并且除了 func 声明之外,他们对这些内容的文档完全空白,这无济于事。我想我已经完成了代码的“骨架”,但不确定 .recordMatchedBlock
和 .queryResultsBlock
.
我有一个 func queryAllNotes(),它应该查询 public 数据库中类型为“Notes”的所有记录和 return 笔记标题及其关联的 cloudID 的元组数组,它只是添加到数据库时赋予它的唯一记录名称。
这是 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
}
根据我的理解,查询 return 的每条记录都会调用 .recordMatchedBlock
,所以我认为它是完整的,但我可能错了。关于 .queryResultBlock
,我的理解是技术上查询一次只能 return 一条记录,这个块基本上告诉查询再次 运行 以获取所有记录的下一条记录.resultLimit
。我该如何构造这个查询?我很想了解每个模块的作用。
这也是针对 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 获取数据变得更加容易。
而不是 CKQueryOperation
你直接调用 records(matching:resultsLimit:)
并将结果映射到你喜欢的任何东西。
一个可能的错误交给了调用者。
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.
旁注:
使用结构而不是元组。不鼓励使用元组作为数据源数组。