CKAsset URLs discarded after backgrounding app in iOS 18

My app uses a temporary singleton to store CKRecords for user profiles, to prevent repeated fetching of profile pics & display usernames during a user's session.

Since iOS 18, after leaving the app in the background for an unspecified period of time & reopening it, the app has started to discard the CKAssets in those 'cached' records.

The records are still there, & the custom fields such as the display username string is still accessible. However the profile pic assets aren't?

This is the code that is displaying the profile picture, could this be something to do with some changes to how CKAssets are given file urls?

 if postOwnerRecord != nil, let imageAsset = postOwnerRecord!.object(forKey: "profilePicture") as? CKAsset, let photoData = NSData(contentsOf:imageAsset.fileURL!) {
            
        if let uiImage = UIImage(data: photoData as Data) {
                
                let imageToUse = Image(uiImage: uiImage)
                Image(uiImage: imageToUse)
                
            }
}

Expected behavior: CKAssets should persist when resuming the app from the background.

Actual behavior: CKAssets are discarded when reopening the app, but custom fields are still accessible.

Question: Is this related to iOS 18, or am I mishandling how CKAssets are cached or their file URLs? Is there a better approach to caching these assets across app sessions? Any pointers or changes would be appreciated.

I've reviewed iOS 18 release notes but didn't find any clear references to changes with CKAsset handling. Any ideas?

Answered by DTS Engineer in 805550022

The fileURL of a CloudKit asset (CKAsset) returned by CloudKit points to a file in the cache, and is only guaranteed to be valid before the delivery closure returns. The system can clear the cache any time after that.

As an example, assuming you use CKQueryOperation to fetch a CloudKit record that contains an asset, the system only guarantees that the asset file is there in the cache before recordMatchedBlock returns.

If you need to use the asset file later, copy the file to a safe place before the closure returns.

In your case, it seems to me that you leave the file in the cache and access that later. If that is the case, the file is not guaranteed to be there.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Accepted Answer

The fileURL of a CloudKit asset (CKAsset) returned by CloudKit points to a file in the cache, and is only guaranteed to be valid before the delivery closure returns. The system can clear the cache any time after that.

As an example, assuming you use CKQueryOperation to fetch a CloudKit record that contains an asset, the system only guarantees that the asset file is there in the cache before recordMatchedBlock returns.

If you need to use the asset file later, copy the file to a safe place before the closure returns.

In your case, it seems to me that you leave the file in the cache and access that later. If that is the case, the file is not guaranteed to be there.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

CKAsset URLs discarded after backgrounding app in iOS 18
 
 
Q