Coder1224
Coder1224

Reputation: 1835

CKAsset in server record contains no fileURL, cannot even check for nil

I am testing a sync conflict when I save a record that contains a CKAsset (simply a JPG image) using CKModifyRecordsOperation with a save policy of .IfServerRecordUnchanged. I am getting the error CKErrorCode.ServerRecordChanged. This CKError returns me useful information for conflict resolution, including the CKRecord I tried to save, and the current server version of the record. The first is in error.userInfo[CKRecordChangedErrorClientRecordKey] the second is in error.userInfo[CKRecordChangedErrorServerRecordKey].

My problem is I am trying to access the server record's CKAsset with this code:

if let photoAsset = rec["myPhoto"] as? CKAsset {
  print("PhotoAsset.fileURL: \(photoAsset.fileURL)")  // BAD_ACCESS ERROR HERE
  self.myPartner.photo = NSData(contentsOfURL: photoAsset.fileURL)
}

I don't get how this is possible. But after further investigating, I print out the client and server CKRecords and the server one is missing the 'path' property.

client CKAsset...myPhoto (modified) -> CKAsset: 0x7b960d90; path=~/tmp/BF185B2C-7A39-4730-9530-9797E843243Aphoto, size=373959, uploadRank=0, uploadReceipt=A92Eg1qoyPG7yrg3, UUID=3C2D5DC8-4FF5-4A81-853B-395FC1C59862, referenceSignature=<012fd149 200fc600 617e3907 88763e3e 5002abbf 5b>, flags=uploaded, wrappedEncryptionKey=, signature=<0134a297 38d52f5f 9275bfba fce5b1a8 3d6b9692 d3>

server CKAsset...myPhoto = CKAsset: 0x7be700d0; referenceSignature=<015337bd 84409893 7c014f46 36248d27 ce911dc3 7a>, size=373959, uploadRank=0, UUID=DF5D2EB4-033C-49A2-AF52-6055B5A44106, wrappedEncryptionKey=<767e7cfd d1e62110 32119ee9 f6f026b3 5bcf0cc3 8053a4de>, signature=<0134a297 38d52f5f 9275bfba fce5b1a8 3d6b9692 d3>

Notice how path=~/tmp/C706423B-A3E8-4051-A9B3-483C718BFBF5photo is missing from the server one? Can anyone explain this? To fix it I try to avoid touching the CKAsset from the server record. I would like to at least be able to check for nil. I wanted to put this out there in case it helps anyone else.

Upvotes: 5

Views: 364

Answers (3)

Alan McCosh
Alan McCosh

Reputation: 151

This seems like the correct behavior, not a bug.

CloudKit informed you that your write operation failed because you weren't working from the latest CKRecord and gave you a non-hydrated version of the server's current CKRecord so you could determine which fields were different from your starting point. The rest is up to you.

If CloudKit returned the fully hydrated server record in the error response for a write operation, it would potentially waste enormous amounts of bandwidth/resources.

That is why CKAssets exist: to separate the size-constrained key-value fields associated with a CKRecord from the unlimited-size binary assets that can be attached to them.

Upvotes: 0

Patrik Vaberer
Patrik Vaberer

Reputation: 666

I'm experiencing this issue as well on iOS 11.2.1 when accessing CKAsset from serverRecord property in CKRecord. It's a little bit frustrating. A workaround is fetching the object once again via func fetch(withRecordID... and then access fileURL.

Upvotes: 0

Archagon
Archagon

Reputation: 2530

Due to the crash on accessing fileURL, this is most likely a framework bug. Probably an oversight on account of the CKRecord being buried in a dictionary. I just follow it up with a regular fetch(withRecordID:).

Upvotes: 0

Related Questions