swift - 了解如何正确执行 CKQueryOperation

标签 swift cloudkit ckquery ckqueryoperation

我是第一次使用 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/

相关文章:

swift - 如何在 Swift 3 中设置 CollectionView 单元格之间的间距?

ios - CKFetchNotificationChangesOperation 返回旧通知

ios - CKQueryOperation resultLimit max 和请求计数

ios - CloudKit复合查询(OR查询)

ios - CloudKit 查询出现奇怪错误

ios - 当用户单击“注销”时,我想将 View Controller 关闭到第一个屏幕

Swift SpriteKit 物理碰撞问题

ios - 试图在我的 UITableView 中返回数组的每个索引

ios - 我可以将 CKRecords 从一个 CKContainer 移动到另一个 CKContainer 吗?

ios - iOS CloudDocsLibrary崩溃(可能是KVO崩溃)