我想确保我理解正确ubiquityIdentityToken。
每个 iCloud 帐户在每个设备上获取的 ubiquityIdentityToken 在该设备上将是一致且唯一的,但在不同设备之间可能会不一致。
这是真的?
有关 的 Apple 文档,请参阅此处ubiquityIdentityToken。
我正在比较 CKRecord 的版本,使用recordChangeTag,我看到随着时间的推移,值从n9(2 个字符)更改为1c1(3 个字符)。
在苹果文档中:
在您自己的代码中,您可以使用更改标记来区分同一记录的两个不同版本。
我想问一下:
当我使用保存策略保存包含CKAsset(只是 JPG 图像)的记录时,我正在测试同步冲突。我收到错误。这会返回用于解决冲突的有用信息,包括我尝试保存的信息以及记录的当前服务器版本。第一个在,第二个在。CKModifyRecordsOperation.IfServerRecordUnchangedCKErrorCode.ServerRecordChangedCKErrorCKRecorderror.userInfo[CKRecordChangedErrorClientRecordKey]error.userInfo[CKRecordChangedErrorServerRecordKey]
我的问题是我尝试使用以下代码访问服务器记录的 CKAsset:
if let photoAsset = rec["myPhoto"] as? CKAsset {
print("PhotoAsset.fileURL: \(photoAsset.fileURL)") // BAD_ACCESS ERROR HERE
self.myPartner.photo = NSData(contentsOfURL: photoAsset.fileURL)
}
Run Code Online (Sandbox Code Playgroud)
我不明白这怎么可能。但经过进一步调查,我打印出了客户端和服务器 CKRecords,而服务器缺少“路径”属性。
客户端 CKAsset...myPhoto (已修改)-> CKAsset:0x7b960d90;路径=~/tmp/BF185B2C-7A39-4730-9530-9797E843243A照片,大小=373959,uploadRank=0,uploadReceipt=A92Eg1qoyPG7yrg3,UUID=3C2D5DC8-4FF5-4A81-853B-395FC1C59862,referenceSignature=<012 fd149 200fc600 617e3907 88763e3e 5002abbf 5b> 、flags=已上传、wrappedEncryptionKey=、签名=<0134a297 38d52f5f 9275bfba fce5b1a8 3d6b9692 d3>
服务器 CKAsset...myPhoto = CKAsset: 0x7be700d0; ReferenceSignature=<015337bd 84409893 7c014f46 36248d27 ce911dc3 7a>,大小=373959,uploadRank=0,UUID=DF5D2EB4-033C-49A2-AF52-6055B5A44106,wrappedEncryptionKey=<767e7cfd d1e62 110 32119ee9 f6f026b3 5bcf0cc3 8053a4de>,签名=<0134a297 38d52f5f 9275bfba fce5b1a8 3d6b9692 d3>
请注意,path=~/tmp/C706423B-A3E8-4051-A9B3-483C718BFBF5photo服务器中缺少什么?谁能解释一下吗?为了解决这个问题,我尝试避免接触服务器记录中的 CKAsset。我希望至少能够检查是否为零。我想把它放在那里以防对其他人有帮助。
标题评论指出CKFetchDatabaseChangesOperation fetchDatabaseChangesCompletionBlock:
“如果服务器返回CKErrorChangeTokenExpired错误,则该previousServerChangeToken值太旧,客户端应该丢弃其本地缓存并重新获取此记录区域中以 nil 开头的更改previousServerChangeToken。”
我想测试这个场景,因此我想生成一个过期的,CKServerChangeToken这样我就可以将其设置previousServerChangeToken为CKFetchDatabaseChangesOperation.
我从私有标头添加了一个 init 方法:
@interface CKServerChangeToken (Private)
- (id)initWithData:(NSData *)data;
@end
Run Code Online (Sandbox Code Playgroud)
并按如下方式使用它:
CKServerChangeToken knownExpiredToken = [[CKServerChangeToken alloc] initWithData:[[NSData alloc] initWithBase64EncodedString:@"AQAAAVl57tUGHv6sgNT9EeaTcQCM+sDHHA==" options:0]];
Run Code Online (Sandbox Code Playgroud)
该字符串是从请求返回的有效更改令牌,我尝试修改它但未成功,例如将我看到的递增数字减少到较低的数字。然而,我设法得到了另一个奇怪的无效参数错误,例如缺少连续标记。如果CloudKit工程师有任何建议,我将不胜感激,谢谢。
在我的 CloudKit 应用程序中,我在存储所有 CKRecord 的私有数据库中创建一个区域。CKRecords 可以有 10 种不同的记录类型,其中一些可以附加 CKAssets。我用来CKFetchRecordZoneChangesOperation查找该区域中的记录更改,并下载它们。我想优化,CKFetchRecordZoneChangesOperation以便只包含desiredKeys在下载中,所以当时我不下载 CKAsset,但似乎没有任何方法可以指定每个记录类型。相反,您似乎只能指定desiredKeyson CKFetchRecordZoneChangesOptions,它是在 zoneID 上设置的。
CKFetchRecordZoneChangesOperation那么,考虑到该区域中有不同类型的记录类型,如何在获取时指定“desiredKeys” ?我在这里缺少一些简单的东西吗?我猜想另一个(彻底的)选项是为每种记录类型创建一个记录区域,但如果有可能的话,我不想走这条路。
谢谢。
iCloud Drive 和 CloudKit 有什么区别?哪个更适合存储手动、定期的应用程序文档备份?我确实看到了这个问题:
iCloud 与 iCloud Drive 与 CloudKit
但它是关于成本而不是实际服务之间的差异。
TLDR 版本:我的应用程序如何知道设备 A 上的 CoreData 对象、设备 B 上的 CoreData 对象和 CloudKit 中的 CKRecord都是相同的记录?
详细版本:
我正在开发一个在本地使用 CoreData 和 CloudKit 在设备之间同步的应用程序。一旦添加了多个设备,我不明白 CoreData 关系和 CloudKit 引用应该如何协同工作。
我所理解的一些真理:
1) 当您创建 CoreData 对象时,它会被分配一个 objectID。您不能在创建时自己分配一个或修改已经存在的一个。从 CoreData 关系字段中,您可以直接访问相关对象,也可以使用方便的方法获取这些相关对象的 objectID。
2)当你创建一个 CloudKit 记录时,你可以给它分配一个 recordName(基本上是一个 CoreData objectID 的 CloudKit 等价物)或者一个默认生成的。CloudKit 引用字段包含一个字符串,它是关联记录的 recordName。
所以这是我的应用程序的工作方式(并且不起作用)
设备 A 首次启动。CoreData 实例化了一堆默认对象,然后用户可以在使用应用程序时对其进行编辑(或添加/删除)。当设置完成并且应用程序确定一切正常时,它会与 CloudKit 同步。它首先查找已存在的所有记录(无),然后使用 CoreData objectID 作为 CloudKit 记录名称将新记录上传到 CloudKit。所以设备 A 上的对象 ID 和 CloudKit 记录名称是相同的。这些不同的对象之间存在多种关系。到目前为止一切顺利 - 这部分工作(仪表板中的修改正确更新核心数据中的关系,反之亦然)。
当设备 B 首次启动时,事情现在就出轨了。CoreData 实例化相同的一组默认对象(具有唯一的 objectID),然后用户可以在使用应用程序时修改或添加/删除这些对象。当设置完成并且一切顺利时,它会与 CloudKit 同步。它从 CloudKit 中提取所有现有记录并更新匹配的本地记录。永远不会根据 recordName <-> …
我正在将 CloudKit 添加到我的应用程序以启用 iCloud 同步。但是我的方法遇到了问题,即在私有数据库上使用执行方法执行查询。
我的方法运行良好,然后我更改了一些相关方法(只需检查 iCloud 是否可用),突然我的执行方法什么也不做。无我的意思是perform(query: )闭包中的任何内容都不会被执行。我在第一行有断点,在下一行有其他断点,但从未设法击中它们。
private static func getAppDetailsFromCloud(completion: @escaping (_ appDetails: [CloudAppDetails]?) -> Void) {
var cloudAppDetails = [CloudAppDetails]()
let privateDatabase = CKContainer.default().privateCloudDatabase
let query = CKQuery(recordType: APPID_Type, predicate: NSPredicate(format: "TRUEPREDICATE"))
privateDatabase.perform(query, inZoneWith: nil) { (records, error) in
if let error = error {
print(error)
completion(nil)
} else {
if let records = records {
for record in records {
let appId = record.object(forKey: APPID_ID_Property) as? Int
let isDeleted = record.object(forKey: APPID_ISDELETED_Property) as? …Run Code Online (Sandbox Code Playgroud) 我正在参与的项目的一部分涉及管理产品的存储。一个Storage对象包含StorageShelf定义货架数量的对象。StorageShelf 又包含一些其他对象,例如StorageLocation确定货架上可容纳的产品数量的对象。所有这些对象都存在于 CoreData 中。我还将Storages和存储StorageShelfs在 CloudKit 数据库中以用于同步目的。
如果我在两台 iPad 上运行我的应用程序,并在其中一台设备上添加带有一些架子的存储,则它会在另一台设备上接收通知并开始处理收到的更新。
我的应用程序中有一个 CloudOperationQueue,其值为maxConcurrentOperationCount1,以确保同时只进行一次更新(这是因为我的应用程序的所有对象,以及超出此问题范围的对象都是高度相互依赖的) 。
不一致的是,这会导致以下SIGABRT错误消息:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Objects should not be both modified and additional'
Run Code Online (Sandbox Code Playgroud)
具体来说,当我在修改收到的架子对象之一后保存上下文时,会发生此错误。哪个货架没有一致性。
问题
这个错误是什么意思,如何调试它?
当用户第一次启动您的应用程序时,CloudKit 创建唯一的用户记录并添加到公共数据库中。出于调试目的,我尝试删除它,以便 CloudKit 可以生成一个与之前不同的新的唯一 ID。
但是,当尝试使用 CloudKit 仪表板删除所述记录时,我收到以下错误:
invalid attempt to delete user records directly
Run Code Online (Sandbox Code Playgroud)
当尝试使用该deleteRecordWithID:方法在代码中删除它时,我遇到了同样的错误。
有谁知道删除用户记录的正确方法吗?有可能吗?是否有其他解决方案可以通过强制创建新记录来解决我的问题?
cloudkit ×10
ios ×8
swift ×3
core-data ×2
icloud ×2
backup ×1
ckasset ×1
ckerror ×1
ckoperation ×1
ckrecordzone ×1
icloud-drive ×1
ios10 ×1
macos ×1
macos-sierra ×1
objective-c ×1