我如何(以及何时)在CKRecord上使用iCloud的encodeSystemFields方法?

goo*_*ate 12 icloud icloud-api cloudkit ios10

encodeSystemFields 当我在本地保存记录时,应该使用数据库.

一旦我导出了这些数据,在反序列化时我必须做些什么吗?

我应该根据该数据中的信息采取哪些方案?

作为一种变体(如果在上一个问题中没有涉及),这些信息对我有何帮助?(我假设数据损坏)

bre*_*les 27

encodeSystemFields可以避免再次从CloudKit获取CKRecord来更新它(禁止记录冲突).

这个想法是:

当您存储从CloudKit检索的记录的数据时(例如,通过CKFetchRecordZoneChangesOperation检索以将记录更改同步到本地存储):

1.)将CKRecord存档到NSData:

let record = ...

// archive CKRecord to NSData
let archivedData = NSMutableData()
let archiver = NSKeyedArchiver(forWritingWithMutableData: archivedData)
archiver.requiresSecureCoding = true
record.encodeSystemFieldsWithCoder(with: archiver)
archiver.finishEncoding()
Run Code Online (Sandbox Code Playgroud)

2.)将archivedData存储在本地(例如,在您的数据库中)与本地记录关联.

如果要将对本地记录所做的更改保存回CloudKit:

1.)从您存储的NSData中取消归档CKRecord:

let archivedData = ... // TODO: retrieved from your local store

// unarchive CKRecord from NSData
let unarchiver = NSKeyedUnarchiver(forReadingWithData: archivedData)  
unarchiver.requiresSecureCoding = true 
let record = CKRecord(coder: unarchiver)
Run Code Online (Sandbox Code Playgroud)

2.)使用该未归档记录作为更改的基础.(即设置更改后的值)

record["City"] = "newCity"
Run Code Online (Sandbox Code Playgroud)

3.)通过CKModifyRecordsOperation将记录保存到CloudKit.


为什么?

来自Apple:

在本地存储记录

如果将记录存储在本地数据库中,请使用encodeSystemFields(with :)方法对记录的元数据进行编码和存储.元数据包含记录ID和更改标记,稍后需要将本地数据库中的记录与CloudKit存储的记录同步.

在CloudKit中将更改保存到CKRecord时,需要将更改保存到服务器的记录中.

您不能只使用相同的recordID创建新的CKRecord,在其上设置值并保存它.如果这样做,您将收到"服务器记录已更改"错误 - 在这种情况下,这是因为现有服务器记录包含缺少本地记录(从头创建)的元数据.

所以你有两个选择来解决这个问题:

  1. 从CloudKit请求CKRecord(使用recordID),对该CKRecord进行更改,然后将其保存回CloudKit.

  2. 使用encodeSystemFields,并在本地存储元数据,取消归档以创建一个"基础"CKRecord,它具有所有适当的元数据,用于将所述CKRecord的更改保存回CloudKit.

#2为您节省了网络往返*.

*假设其他设备在此期间未修改记录 - 这也是此数据可帮助您防范的内容.如果另一台设备在您上次检索它的时间和您尝试保存它的时间之间修改了记录,CloudKit将(默认情况下)拒绝"服务器记录已更改"的记录保存尝试.这是以适合您的应用和数据模型的方式执行冲突解决的线索.(通常,通过从CloudKit获取新服务器记录并在再次尝试保存之前将适当的值更改重新应用于该CKRecord.)

注意:每次向/从CloudKit保存/检索更新的CKRecord时,您必须记住更新本地存储的存档CKRecord.

  • @LamonteCristo:`encodeSystemFields`****仅编码CKRecord的系统元数据值,**不**您设置的任何键+值.因此,您绝对应该单独从数据库中的CKRecord记录"数据"(您设置的字段) - 这不是多余的. (3认同)