阅读背景:

使用iCloud文档存储的最佳方式

来源:互联网 

I am currently using local storage in my iOS App. The user data is stored in the Document Directory and now I am planning to use iCloud Documents storage instead.

我目前在我的iOS App中使用本地存储,用户数据存储在文档目录中,现在我计划使用iCloud文档存储。

Here is how I intend to do it :

我打算这样做:

  1. Checking if iCloud is available on the device

    检查设备上是否有iCloud可用

  2. If yes, use URLForUbiquityContainerIdentifier to get the iCloud container URL

    如果是,使用URLForUbiquityContainerIdentifier来获取iCloud容器URL

  3. Save new files and documents to this new URL

    将新文件和文档保存到这个新URL

For that I am using this code that will return the URL of the document folder (iCloud or local)

为此,我使用的代码将返回文档文件夹的URL (iCloud或local)

  class CloudDataManager {

    class  func getDocumentDiretoryURL() -> NSURL {

   let localDocumentsURL = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: .UserDomainMask).last! as NSURL
   let iCloudDocumentsURL = NSFileManager.defaultManager().URLForUbiquityContainerIdentifier(nil)?.URLByAppendingPathComponent("Documents")

       if userDefault.boolForKey("useCloud") && iCloudDocumentsURL != nil  {
          return iCloudDocumentsURL!
       } else {
          return localDocumentsURL
   }
  }
 }

Is it the best practice? I am worried problems will occur if one day iCloud isn't available so the local directory will be used instead of the cloud container and will be empty. Thank you.

这是最好的练习吗?我担心,如果有一天iCloud无法使用,那么本地目录将代替云容器而被使用,并且将是空的,那么问题将会出现。谢谢你!

3 个解决方案

#1


10  

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)
  • iCloud将被默认激活(如果可能的话)
  • The user can use an UISwitch to disable/enable iCloud in the App
  • 用户可以使用UISwitch(用户名)来禁用或启用iCloud
  • When the user disable iCloud, all the iCloud files will be transferred locally
  • 当用户禁用iCloud时,所有的iCloud文件将被本地传输
  • When the user enable iCloud, all the local files will be transferred in the iCloud Ubiquity container
  • 当用户启用iCloud时,所有本地文件将在iCloud Ubiquity容器中传输
  • 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).

我想几乎每个人都将使用iCloud,一切都将是透明和无痛的。无论如何,我同步的文件非常小,所以应该可以正常工作(到目前为止)。

I have 5 simples methods:

我有5种简化方法:

  1. Method to check if iCloud is available
  2. 方法检查iCloud是否可用
  3. Method to return the Document URL according to user choice (iCloud OR Local)
  4. 方法根据用户选择返回文档URL (iCloud或Local)
  5. Method to delete all files in a Directory (files used by the app)
  6. 方法删除目录中的所有文件(应用程序使用的文件)
  7. Method to move files from local dir to iCloud container
  8. 方法将文件从本地目录移动到iCloud容器
  9. Method to move fies from iCloud container to local dir
  10. 方法从iCloud容器移动到本地目录

Here is my class that handle the issue

这是我的班级处理这个问题

class CloudDataManager {

static let sharedInstance = CloudDataManager() // Singleton

struct 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 thread

func 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 enabled

func isCloudEnabled() -> Bool {
    if DocumentsDirectory.iCloudDocumentsURL != nil { return true }
    else { return false }
}

// Delete All files at URL

func 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 merging

func 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 merging

func 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)")
            }
        }
    }
}



}

#2


1  

Check this link: iCloud basics and code sample

查看这个链接:iCloud基础服务和代码示例

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.

如果存储的信息很简单,最好使用NSUserDefaults。你不想向iCloud索取基本信息。

#3


1  

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..

对于那些想使用SWIFT 3的人:注意:我只是复制数据而不是移动数据。但是目标路径在复制数据之前被清除。

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)")
                }
            }
        }
    }



}

分享到: