In this article, I am going to guide you through a step by step process of restoring your application’s data backed up on iCloud and tracking the download progress on the way. Please note that this article is an extension of a previously posted article where I have gone through the process of backing up your application’s data on iCloud. If you have not read through the first part of this series, please stop right here and go through the first part of the article here.
import Foundation
class Restore: NSObject {
var query: NSMetadataQuery!
override init() {
super.init()
}
}
Next, let’s initialise our query by adding a new method initialiseQuery() and calling it from our viewDidLoad() method. This will initialise our query and provide a predicate to search for our sample.mp4 file on the iCloud drive.
import Foundation
class Restore: NSObject {
var query: NSMetadataQuery!
override init() {
super.init()
initialiseQuery()
}
func initialiseQuery() {
query = NSMetadataQuery.init()
query.operationQueue = .main
query.searchScopes = [NSMetadataQueryUbiquitousDataScope]
query.predicate = NSPredicate(format: "%K LIKE %@", NSMetadataItemFSNameKey, "sample.mp4")
}
}
Step 2, adding notification observers: Now, we are going to add notification observers to listen for the updates returned by our query. Specifically, we will listen to NSMetadataQueryDidStartGathering, which will let us know when the query starts gathering information and NSMetadataQueryGatheringProgress, giving us the progress of the gathering and NSMetadataQueryDidUpdate, that’ll be called each time an update about the operation is available.
import Foundation
class Restore: NSObject {
var query: NSMetadataQuery!
override init() {
super.init()
initialiseQuery()
addNotificationObservers()
}
func initialiseQuery() {
query = NSMetadataQuery.init()
query.operationQueue = .main
query.searchScopes = [NSMetadataQueryUbiquitousDataScope]
query.predicate = NSPredicate(format: "%K LIKE %@", NSMetadataItemFSNameKey, "sample.mp4")
}
func addNotificationObservers() {
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSMetadataQueryDidStartGathering, object: query, queue: query.operationQueue) { (notification) in
self.processCloudFiles()
}
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSMetadataQueryGatheringProgress, object: query, queue: query.operationQueue) { (notification) in
self.processCloudFiles()
}
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSMetadataQueryDidUpdate, object: query, queue: query.operationQueue) { (notification) in
self.processCloudFiles()
}
}
}
Now that we have added our observers, let’s add a function to process the information. Let us add a function called processCloudFiles() where we are going to process the NSMetadataQuery updates.
@objc func processCloudFiles() {
if query.results.count == 0 { return }
var fileItem: NSMetadataItem?
var fileURL: URL?
for item in query.results {
guard let item = item as? NSMetadataItem else { continue }
guard let fileItemURL = item.value(forAttribute: NSMetadataItemURLKey) as? URL else { continue }
if fileItemURL.lastPathComponent.contains("sample.mp4") {
fileItem = item
fileURL = fileItemURL
}
}
try? FileManager.default.startDownloadingUbiquitousItem(at: fileURL!)
if let fileDownloaded = fileItem?.value(forAttribute: NSMetadataUbiquitousItemDownloadingStatusKey) as? String, fileDownloaded == NSMetadataUbiquitousItemDownloadingStatusCurrent {
query.disableUpdates()
query.operationQueue?.addOperation({ [weak self] in
self?.query.stop()
})
print("Download complete")
} else if let error = fileItem?.value(forAttribute: NSMetadataUbiquitousItemDownloadingErrorKey) as? NSError {
print(error.localizedDescription)
} else {
if let keyProgress = fileItem?.value(forAttribute: NSMetadataUbiquitousItemPercentDownloadedKey) as? Double {
print("File downloaded percent ---", keyProgress)
}
}
}
Let’s go through the function above step by step. We are iterating the query.results and fetching the NSMetadataItem and URL for the file uploaded on iCloud. Once we have our fileURL, we are going to start the download from iCloud.
Next, to track the progress of the download, we are checking for two keys on the fileItem, which is an instance of our NSMetadataItem. These keys, NSMetadataUbiquitousItemDownloadingStatusKey and NSMetadataUbiquitousItemDownloadingStatusCurrent gives us the state of the downloading and the state of the downloaded file (if any) in our local iCloud directory.
To get the progress of downloading, we call NSMetadataUbiquitousItemPercentDownloadedKey on our fileItem, which returns us the progress as a Double value.
Step 3, adding a method to start download: Now, finally add a getBackup() method in our Restore.swift file, in which we will write the code to start the download process.
func getBackup() {
query.operationQueue?.addOperation({ [weak self] in
self?.query.start()
self?.query.enableUpdates()
})
}
Step 4, adding a button to start the download: Let us now move to our ViewController.swift file and add a new button to start the download of the iCloud file. Add the following code in your viewDidLoad() method just below the code where the uploadButton is added.
let downloadBtn = UIButton(frame: CGRect(x: UIScreen.main.bounds.midX - 150, y: button.frame.maxY + 30, width: 300, height: 40))
downloadBtn.setTitle("Download from iCloud", for: .normal)
downloadBtn.addTarget(self, action: #selector(self.downloadFromCloud), for: .touchUpInside)
view.addSubview(downloadBtn)
If you followed all the steps correctly, your ViewController.swift file should appear as follows:
All right then! Everything looks good so far, it’s time to now test out the code that we have written and see it in action.
Once we run the code and take a backup as described in the previous article, we could verify the file was indeed uploaded to the iCloud drive. Now, we are going to switch to our other phone, login into the same iCloud account with which we took the backup and start downloading the file. You’ll see with some progress the file is downloaded on the new device and is visible in its iCloud directory.
Conclusion Backing up our data to iCloud and restoring from iCloud is really not that difficult if we follow the appropriate steps. I hope I was able to help you with the process, let me know if you have any questions. Cheers!