这是我想要做的。我有一个带有两个视图的简单日记应用程序:一个列出条目标题的tableView和一个有标题文本字段的viewController,以及一个用于文本正文的textView(以及一个保存到cloudKit的保存按钮)。在viewController上,我点击保存,记录保存到cloudKit,并成功添加到tableView。这一切都很好。
我希望能够编辑/更新日记帐分录。但是当我回到日志条目,以任何方式更改它,然后再次点击保存时,应用程序返回到带有更新条目的tableView控制器,但是cloudKit会创建一个与我想要编辑的条目分开的新条目。然后当我重新加载应用程序时,我的fetchRecords函数会获取cloudKit创建的任何额外记录。
问题:如何在不在cloudKit中创建新条目的情况下编辑/更新现有日记帐分录?
如果您需要其他内容来进一步澄清我的问题,请告诉我。 谢谢!
以下是我的cloudKit功能:
import Foundation
import CloudKit
class CloudKitManager {
let privateDB = CKContainer.default().publicCloudDatabase //Since this is a journaling app, we'll make it private.
func fetchRecordsWith(type: String, completion: @escaping ((_ records: [CKRecord]?, _ error: Error?) -> Void)) {
let predicate = NSPredicate(value: true) // Like saying I want everything returned to me with the recordType: type. This isn't a good idea if you have a massive app like instagram because you don't want all posts ever made to be loaded, just some from that day and from your friends or something.
let query = CKQuery(recordType: type, predicate: predicate)
privateDB.perform(query, inZoneWith: nil, completionHandler: completion) //Allows us to handle the completion in the EntryController to maintain proper MVC.
}
func save(records: [CKRecord], perRecordCompletion: ((_ record: CKRecord?, _ error: Error?) -> Void)?, completion: ((_ records: [CKRecord]?, _ error: Error?) -> Void)?) {
modify(records: records, perRecordCompletion: perRecordCompletion, completion: completion )
}
func modify(records: [CKRecord], perRecordCompletion: ((_ record: CKRecord?, _ error: Error?) -> Void)?, completion: ((_ records: [CKRecord]?, _ error: Error?) -> Void)?) {
let operation = CKModifyRecordsOperation(recordsToSave: records, recordIDsToDelete: nil)
operation.savePolicy = .ifServerRecordUnchanged //This is what updates certain changes within a record.
operation.queuePriority = .high
operation.qualityOfService = .userInteractive
operation.perRecordCompletionBlock = perRecordCompletion
operation.modifyRecordsCompletionBlock = { (records, _, error) in
completion?(records, error)
}
privateDB.add(operation) //This is what actually saves your data to the database on cloudkit. When there is an operation, you need to add it.
}
}
这是我的模型控制器,我正在使用我的cloudKit功能:
import Foundation
import CloudKit
let entriesWereSetNotification = Notification.Name("entriesWereSet")
class EntryController {
private static let EntriesKey = "entries"
static let shared = EntryController()
let cloudKitManager = CloudKitManager()
init() {
loadFromPersistentStorage()
}
func addEntryWith(title: String, text: String) {
let entry = Entry(title: title, text: text)
entries.append(entry)
saveToPersistentStorage()
}
func remove(entry: Entry) {
if let entryIndex = entries.index(of: entry) {
entries.remove(at: entryIndex)
}
saveToPersistentStorage()
}
func update(entry: Entry, with title: String, text: String) {
entry.title = title
entry.text = text
saveToPersistentStorage()
}
// MARK: Private
private func loadFromPersistentStorage() {
cloudKitManager.fetchRecordsWith(type: Entry.TypeKey) { (records, error) in
if let error = error {
print(error.localizedDescription)
}
guard let records = records else { return } //Make sure there are records.
let entries = records.flatMap({Entry(cloudKitRecord: $0)})
self.entries = entries //This is connected to the private(set) property "entries"
}
}
private func saveToPersistentStorage() {
let entryRecords = self.entries.map({$0.cloudKitRecord})
cloudKitManager.save(records: entryRecords, perRecordCompletion: nil) { (records, error) in
if error != nil {
print(error?.localizedDescription as Any)
return
} else {
print("Successfully saved records to cloudKit")
}
}
}
// MARK: Properties
private(set) var entries = [Entry]() {
didSet {
DispatchQueue.main.async {
NotificationCenter.default.post(name: entriesWereSetNotification, object: nil)
}
}
}
}
答案 0 :(得分:0)
以下是一些可能有用的线程。
如果您在本地缓存数据,您将使用encodesystemfields方法创建一个新的CKRecord,它将更新服务器上的现有CKRecord。
How (and when) do I use iCloud's encodeSystemFields method on CKRecord?
您似乎没有在本地缓存。我没有使用编码系统字段的经验,但看起来你必须将记录拉下来并将其保存在方便方法的完成处理程序中: