Swift - App file not showing in iCloud Drive after sync

daydr3am3r Source

Unable to transfer files between app and iCloud

I have a small quiz app and I need to save the results to iCloud in order to restore them if the user reinstalls the app.

So I used the following logic to sync the data:

When the user starts the app, check if there are any files in DocumentsDirectory.

Case 1 - Not first run:

  • File found
  • Parse file

Case 2 - First run on the device:

  • File NOT found
  • Try to download file from iCloud
  • File found
  • Download OK
  • Parse file

Case 3 - First time use:

  • File NOT found
  • Try to download file from iCloud
  • File NOT found
  • Ignore

if(!checkIfUserDataExists())
{
    print("File does not exist")
    cloudDataManager.copyFileToLocal()
}

if(checkIfUserDataExists())
{
    print("File exists")
    parseUserDataJSON.readUserDataJSONFromFile()
}

Then the user starts using the app and takes the quiz. On save:

  • Export / Save JSON file (UserData.json)
  • Save to iCloud (if iCloud is enabled)

DataSingleton.sharedInstance.saveCurrentUserSession(userSession: newUserSession!)

self.exportUserDataJSON.createUserDataJSON()

if(self.cloudDataManager.isCloudEnabled())
{
    self.cloudDataManager.copyFileToCloud()
}

The local part works just fine but the sync part is a bit tricky.

When I try to save the file to iCloud, it seems to be working and if I check on my device in Settings > Apple ID > iCloud > Manage Storage, I see the UserData.json file. Moreover, with every new quiz submission, the size increases.

enter image description here

So in order to test this, I enablet iTunes Sharing and I deleted the data file then run the app. This seemed to be working as indended in Case 2.

However, if I uninstall the app and try again, it goes in Case 3 but the file found on iCloud is not called UserData.json but .UserData.json.icloud. It does seem to download the file and I get no error yet the file is not visible in iTunes, via iTunes Sharing, nor are the results.

import UIKit

class CloudDataManager
{
    static let documentsDirectoryURL : NSURL? = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: .userDomainMask).last! as NSURL
    static let iCloudDocumentsURL : NSURL? = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents") as NSURL?


    /*
    // MARK: - Check if iCloud sync is enabled
    */

    func isCloudEnabled() -> Bool
    {
        print("CloudDataManager > isCloudEnabled")

        if CloudDataManager.iCloudDocumentsURL != nil
        {
            print("iCloud sync is enabled")

            return true
        }
        else
        {
            print("iCloud sync is disabled")

            return false
        }
    }


    /*
    // MARK: - Delete all files in a Directory
    */

    func deleteFilesInDirectory(url: NSURL?)
    {
        print("CloudDataManager > deleteFilesInDirectory")

        let fileManager = FileManager.default
        let enumerator = fileManager.enumerator(atPath: url!.path!)
        while let file = enumerator?.nextObject() as? String
        {
            do
            {
                try fileManager.removeItem(at: url!.appendingPathComponent(file)!)
                print("Files deleted")
            }
            catch let error as NSError
            {
                print("Failed to delete files : \(error)")
            }
        }
    }


    /*
    // MARK: - Copy all files in DocumentsDirectory to iCloud
    */

    func copyFileToCloud()
    {
        print("CloudDataManager > copyFileToCloud")

        if isCloudEnabled()
        {
            deleteFilesInDirectory(url: CloudDataManager.iCloudDocumentsURL!)

            let fileManager = FileManager.default
            let enumerator = fileManager.enumerator(atPath: CloudDataManager.documentsDirectoryURL!.path!)
            while let file = enumerator?.nextObject() as? String
            {
                do
                {
                    try fileManager.copyItem(at: CloudDataManager.documentsDirectoryURL!.appendingPathComponent(file)!,
                                             to: CloudDataManager.iCloudDocumentsURL!.appendingPathComponent(file)!)

                    print("Copied to iCloud")
                }
                catch let error as NSError
                {
                    print("Failed to copy file to Cloud : \(error)")
                }
            }
        }
        else
        {
            print("iCloud sync disabled")
        }
    }


    /*
    // MARK: - Copy all files in iCloud to DocumentsDirectory
    */

    func copyFileToLocal()
    {
        print("CloudDataManager > copyFileToLocal")

        if isCloudEnabled()
        {
            deleteFilesInDirectory(url: CloudDataManager.documentsDirectoryURL!)

            let fileManager = FileManager.default
            let enumerator = fileManager.enumerator(atPath: CloudDataManager.iCloudDocumentsURL!.path!)
            while let file = enumerator?.nextObject() as? String
            {
                do
                {                       
                    try fileManager.copyItem(at: CloudDataManager.iCloudDocumentsURL!.appendingPathComponent(file)!,
                                             to: CloudDataManager.documentsDirectoryURL!.appendingPathComponent(file)!)

                    print("Copied to local dir")
                }
                catch let error as NSError
                {
                    print("Failed to copy file to local dir : \(error)")
                }
            }
        }
        else
        {
            print("iCloud sync disabled")
        }
    }
}

Any ideas on what am I doing wrong? Also, why does it seem to work when I only delete the JSON file from DocumentsDirectory but not when I am reinstalling the app?

iosswifticloudnsdocumentdirectoryicloud-documents

Answers

comments powered by Disqus