Reputation: 65
I'm trying to store files on the users iCloud Drive. After I save the file on their iCloud drive, I can retrieve it, as long as I don't reinstall the App. I store the paths to the files inside NSUbiquitousKeyValueStore.
Code to save the files:
let data = UIImagePNGRepresentation(finalImage)
let filename = "sticker\((NSUbiquitousKeyValueStore.default().longLong(forKey: "stickerCount"))+1).png"
let filenamePath = self.getDocumentsDirectory().appendingPathComponent(filename)
NSUbiquitousKeyValueStore.default().set(NSUbiquitousKeyValueStore.default().longLong(forKey: "stickerCount")+1, forKey: "stickerCount")
var filenames : NSMutableArray!
if !(NSUbiquitousKeyValueStore.default().bool(forKey: "createdArray")){
NSUbiquitousKeyValueStore.default().set(true, forKey: "createdArray")
filenames = NSMutableArray()
}else{
filenames = (NSUbiquitousKeyValueStore.default().array(forKey: "fileNames")! as NSArray).mutableCopy() as! NSMutableArray
}
filenames.add(filename)
NSUbiquitousKeyValueStore.default().set(filenames, forKey: "fileNames")
NSUbiquitousKeyValueStore.default().synchronize()
try? data?.write(to: filenamePath)
This is the code to get the files:
func loadTheStickers() {
stickerNames.removeAllObjects()
stickers.removeAllObjects()
var filenames : NSMutableArray!
if !(NSUbiquitousKeyValueStore.default().bool(forKey: "createdArray")){
NSUbiquitousKeyValueStore.default().set(true, forKey: "createdArray")
filenames = NSMutableArray()
}else{
filenames = (NSUbiquitousKeyValueStore.default().array(forKey: "fileNames")! as NSArray).mutableCopy() as! NSMutableArray
}
for stickerName in filenames {
stickerNames.add(stickerName)
let url = getDocumentsDirectory().appendingPathComponent(stickerName as! String)
stickers.add(url)
}
}
And I get the URLS, so the NSUbiquitousKeyValueStore working properly, however if I reinstall the App, the imageFromUrl won't return the image so it isnt there. I simply use this line of code:
cell.imageView.image = UIImage(contentsOfFile: (stickers[indexPath.row] as! URL).path)
and again it works perfectly until I try to reinstall the app.
Here is the Class that I use to get the path to the iCloud Directory:
class CloudDataManager {
static let sharedInstance = CloudDataManager() // Singleton
struct DocumentsDirectory {
static let localDocumentsURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupID)
static let iCloudDocumentsURL = FileManager.default.url(forUbiquityContainerIdentifier: iCloudContainerID)?.appendingPathComponent("Documents")
}
// Return the Document directory (Cloud OR Local)
// To do in a background thread
func getDocumentDiretoryURL() -> URL {
if isCloudEnabled() {
if !FileManager.default.fileExists(atPath: (DocumentsDirectory.iCloudDocumentsURL?.path)!){
do {
try FileManager.default.createDirectory(at: DocumentsDirectory.iCloudDocumentsURL!, withIntermediateDirectories: true, attributes: nil)
}catch{
NSLog("Error")
}
}
NSLog("\(DocumentsDirectory.iCloudDocumentsURL!)")
return DocumentsDirectory.iCloudDocumentsURL!
} else {
NSLog("\(DocumentsDirectory.localDocumentsURL!)")
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)")
}
}
}
}
}
and I've checked, it return the correct URL for the iCloud Document directory. So my question is where is the problem, how could I correct the code, so the files are availabla after reinstalling the app or on other devices, becaise atm the iCloud directory isnt better than simply storing in the local Documents directory.
Upvotes: 0
Views: 711
Reputation: 65
After long research, I've managed to solve the problem. You have to manually provoke iCloud to download the items from the cloud, it'll upload automatically, but not download.
You have to use the following line for all the items:
FileManager.default.startDownloadingUbiquitousItem(at: url)
So the downloading code in the Appdelegates application:didfinish... method now looks like this:
var filenames : NSMutableArray!
if !(NSUbiquitousKeyValueStore.default().bool(forKey: "createdArray")){
NSUbiquitousKeyValueStore.default().set(true, forKey: "createdArray")
filenames = NSMutableArray()
}else{
filenames = (NSUbiquitousKeyValueStore.default().array(forKey: "fileNames")! as NSArray).mutableCopy() as! NSMutableArray
}
for stickerName in filenames {
let url = getDocumentsDirectory().appendingPathComponent(stickerName as! String)
if !FileManager.default.fileExists(atPath: url.path){
do {
try FileManager.default.startDownloadingUbiquitousItem(at: url)
}catch{
NSLog(error.localizedDescription)
}
}
}
Upvotes: 1