【发布时间】:2018-04-15 08:29:21
【问题描述】:
这就是我想要做的。我有一个简单的日记应用程序,它有两个视图:一个 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)
}
}
}
}
【问题讨论】:
-
您是否检查过,如果您更新日记帐分录,那么
record的recordID是否保持不变?如果recordID相同,则CloudKit 不会创建新记录... -
@Ladislav 我在 cloudKit 仪表板上看不到任何记录 ID。
-
每条记录都有
Record Name,这是您使用CKRecordID(recordName: "recordName")或CKRecordID(recordName: "recordName", zoneID: zone)为CloudKit 条目创建新的CKRecordID时的名称 -
哦,好的,我明白你在说什么。因此,当我尝试更新记录时,会创建具有新记录 ID 的新记录。我如何确保 cloudKit 知道使用特定记录 ID 的唯一更新记录?谢谢 - 我对此很陌生!
-
在您的
modify方法中,您有这个CKModifyRecordsOperation(recordsToSave: records, recordIDsToDelete: nil),记录是[CKRecord]的数组,因此您要更新的每条记录确保它的record.recordID.recordName相同而不是一个新的......