Best way to use iCloud Documents Storage Best way to use iCloud Documents Storage swift swift

Best way to use iCloud Documents Storage


Thanks to the comment above and with further readings, I've find a way to solve my problem.

Here is how I decided to do it:

  • iCloud will be activated by default (if possible)
  • The user can use an UISwitch to disable/enable iCloud in the App
  • When the user disable iCloud, all the iCloud files will be transferred locally
  • When the user enable iCloud, all the local files will be transferred in the iCloud Ubiquity container
  • No data merging

Like this data will not be lost.

I guess almost everyone will use iCloud and everything will be transparent and painless. Anyway the files I sync are pretty small so it should work fine (so far it does).

I have 5 simples methods:

  1. Method to check if iCloud is available
  2. Method to return the Document URL according to user choice (iCloud OR Local)
  3. Method to delete all files in a Directory (files used by the app)
  4. Method to move files from local dir to iCloud container
  5. Method to move fies from iCloud container to local dir

Here is my class that handle the issue

class CloudDataManager {static let sharedInstance = CloudDataManager() // Singletonstruct DocumentsDirectory {    static let localDocumentsURL: NSURL? = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: .UserDomainMask).last! as NSURL   static let iCloudDocumentsURL: NSURL? = NSFileManager.defaultManager().URLForUbiquityContainerIdentifier(nil)?.URLByAppendingPathComponent("Documents")}// Return the Document directory (Cloud OR Local)// To do in a background threadfunc getDocumentDiretoryURL() -> NSURL {    print(DocumentsDirectory.iCloudDocumentsURL)    print(DocumentsDirectory.localDocumentsURL)    if userDefault.boolForKey("useCloud") && isCloudEnabled()  {        return DocumentsDirectory.iCloudDocumentsURL!    } else {        return DocumentsDirectory.localDocumentsURL!    }}// Return true if iCloud is enabledfunc isCloudEnabled() -> Bool {    if DocumentsDirectory.iCloudDocumentsURL != nil { return true }    else { return false }}// Delete All files at URLfunc deleteFilesInDirectory(url: NSURL?) {    let fileManager = NSFileManager.defaultManager()    let enumerator = fileManager.enumeratorAtPath(url!.path!)    while let file = enumerator?.nextObject() as? String {        do {            try fileManager.removeItemAtURL(url!.URLByAppendingPathComponent(file))            print("Files deleted")        } catch let error as NSError {            print("Failed deleting files : \(error)")        }    }}// Move local files to iCloud// iCloud will be cleared before any operation// No data mergingfunc moveFileToCloud() {    if isCloudEnabled() {        deleteFilesInDirectory(DocumentsDirectory.iCloudDocumentsURL!) // Clear destination        let fileManager = NSFileManager.defaultManager()        let enumerator = fileManager.enumeratorAtPath(DocumentsDirectory.localDocumentsURL!.path!)        while let file = enumerator?.nextObject() as? String {            do {                try fileManager.setUbiquitous(true,                    itemAtURL: DocumentsDirectory.localDocumentsURL!.URLByAppendingPathComponent(file),                    destinationURL: DocumentsDirectory.iCloudDocumentsURL!.URLByAppendingPathComponent(file))                print("Moved to iCloud")            } catch let error as NSError {                print("Failed to move file to Cloud : \(error)")            }        }    }}// Move iCloud files to local directory// Local dir will be cleared// No data mergingfunc moveFileToLocal() {    if isCloudEnabled() {        deleteFilesInDirectory(DocumentsDirectory.localDocumentsURL!)        let fileManager = NSFileManager.defaultManager()        let enumerator = fileManager.enumeratorAtPath(DocumentsDirectory.iCloudDocumentsURL!.path!)        while let file = enumerator?.nextObject() as? String {            do {                try fileManager.setUbiquitous(false,                    itemAtURL: DocumentsDirectory.iCloudDocumentsURL!.URLByAppendingPathComponent(file),                    destinationURL: DocumentsDirectory.localDocumentsURL!.URLByAppendingPathComponent(file))                print("Moved to local dir")            } catch let error as NSError {                print("Failed to move file to local dir : \(error)")            }        }    }}}


for those who wants to use SWIFT 3:NOTE: Instead of moving the data I just do copy. But the destination path is cleared before copy data there..

class CloudDataManager {    static let sharedInstance = CloudDataManager() // Singleton    struct DocumentsDirectory {        static let localDocumentsURL = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: .userDomainMask).last!        static let iCloudDocumentsURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")    }    // Return the Document directory (Cloud OR Local)    // To do in a background thread    func getDocumentDiretoryURL() -> URL {        if isCloudEnabled()  {            return DocumentsDirectory.iCloudDocumentsURL!        } else {            return DocumentsDirectory.localDocumentsURL        }    }    // Return true if iCloud is enabled    func isCloudEnabled() -> Bool {        if DocumentsDirectory.iCloudDocumentsURL != nil { return true }        else { return false }    }    // Delete All files at URL    func deleteFilesInDirectory(url: URL?) {        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 deleting files : \(error)")            }        }    }    // Copy local files to iCloud    // iCloud will be cleared before any operation    // No data merging    func copyFileToCloud() {        if isCloudEnabled() {            deleteFilesInDirectory(url: DocumentsDirectory.iCloudDocumentsURL!) // Clear all files in iCloud Doc Dir            let fileManager = FileManager.default            let enumerator = fileManager.enumerator(atPath: DocumentsDirectory.localDocumentsURL.path)            while let file = enumerator?.nextObject() as? String {                do {                    try fileManager.copyItem(at: DocumentsDirectory.localDocumentsURL.appendingPathComponent(file), to: DocumentsDirectory.iCloudDocumentsURL!.appendingPathComponent(file))                    print("Copied to iCloud")                } catch let error as NSError {                    print("Failed to move file to Cloud : \(error)")                }            }        }    }    // Copy iCloud files to local directory    // Local dir will be cleared    // No data merging    func copyFileToLocal() {        if isCloudEnabled() {            deleteFilesInDirectory(url: DocumentsDirectory.localDocumentsURL)            let fileManager = FileManager.default            let enumerator = fileManager.enumerator(atPath: DocumentsDirectory.iCloudDocumentsURL!.path)            while let file = enumerator?.nextObject() as? String {                do {                    try fileManager.copyItem(at: DocumentsDirectory.iCloudDocumentsURL!.appendingPathComponent(file), to: DocumentsDirectory.localDocumentsURL.appendingPathComponent(file))                    print("Moved to local dir")                } catch let error as NSError {                    print("Failed to move file to local dir : \(error)")                }            }        }    }}


Check this link: iCloud basics and code sample

If the information that you are storing are simple, it's better to use NSUserDefaults. You don't want to ask iCloud for basic information.