重新安装应用程序后如何从 iCloud 中的文件中获取数据?
How to get data from a file in iCloud after reinstalling the app?
应用程序使用iCloud存储符合Codable协议的对象NSKeyedArchiver/NSKeyedUnarchiver。
设备之间的同步是可以的,除非在设备上重新安装应用程序(或安装在新设备上)并且包含数据的文件存在 - 在这种情况下
NSKeyedUnarchiver.unarchiveObject(withFile: filePathe) return 无。
当我在新设备上安装应用程序(在同一设备上重新安装)时,如何从 iCloud 的现有文件中获取数据?
class ViewController: UIViewController {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var weightLabel: UILabel!
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var weightTextField: UITextField!
var iCloudContainer: URL? {
return FileManager().url(forUbiquityContainerIdentifier: nil)
}
func getFilePath(container: URL, fileName: String) -> String {
let filePath = container.appendingPathComponent(fileName).path
return filePath
}
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func fetchButtonPressed(_ sender: UIButton) {
let container = self.iCloudContainer
let filePathe = getFilePath(container: container!, fileName: "Person")
if let jsonData = NSKeyedUnarchiver.unarchiveObject(withFile: filePathe) as? Data {
if let person = try? JSONDecoder().decode(Person.self, from: jsonData) {
nameLabel.text = person.name
weightLabel.text = String(person.weight)
} else {
nameLabel.text = "No data loaded"
weightLabel.text = "No data loaded"
}
} else {
nameLabel.text = "No data loaded"
weightLabel.text = "No data loaded"
}
}
@IBAction func saveButtonPressed(_ sender: UIButton) {
let container = self.iCloudContainer
let filePathe = getFilePath(container: container!, fileName: "Person")
let person = Person(name: nameTextField.text!, weight: Double(weightTextField.text!)!)
let jsonData = try? JSONEncoder().encode(person)
NSKeyedArchiver.archiveRootObject(jsonData!, toFile: filePathe)
}
要将数据从 iCloud 容器获取到本地 Ubiquity 容器,您应该使用元数据从 iCloud 查找项目并将其下载到设备。
lazy var metadataQuery : NSMetadataQuery = {
let query = NSMetadataQuery()
query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
query.predicate = NSPredicate(format: "%K CONTAINS %@", NSMetadataItemFSNameKey, "List")
NotificationCenter.default.addObserver(self, selector: #selector(didFinishGathering), name: NSNotification.Name.NSMetadataQueryDidUpdate, object: query)
NotificationCenter.default.addObserver(self, selector: #selector(didFinishGathering), name: NSNotification.Name.NSMetadataQueryDidFinishGathering, object: query)
return query
}()
override func viewDidLoad() {
super.viewDidLoad()
self.metadataQuery.start()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func didFinishGathering(notification: Notification?) {
let query = notification?.object as? NSMetadataQuery
query?.enumerateResults { (item: Any, index: Int, stop: UnsafeMutablePointer<ObjCBool>) in
let metadataItem = item as! NSMetadataItem
if isMetadataItemDownloaded(item: metadataItem) == false {
let url = metadataItem.value(forAttribute: NSMetadataItemURLKey) as! URL
try? FileManager.default.startDownloadingUbiquitousItem(at: url)
}
}
guard let queryresultsCount = query?.resultCount else { return }
for index in 0..<queryresultsCount {
let item = query?.result(at: index) as? NSMetadataItem
let itemName = item?.value(forAttribute: NSMetadataItemFSNameKey) as! String
let container = filesCoordinator.iCloudContainer
let filePath = filesCoordinator.getFilePath(container: container!, fileName: "TaskList")
let addressPath = filesCoordinator.getFilePath(container: container!, fileName: "CategoryList")
if itemName == "TaskList" {
if let jsonData = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Data {
if let person = try? JSONDecoder().decode(Person.self, from: jsonData) {
nameLabel.text = person.name
weightLabel.text = String(person.weight)
} else {
nameLabel.text = "NOT decoded"
weightLabel.text = "NOT decoded"
}
} else {
nameLabel.text = "NOT unarchived"
weightLabel.text = "NOT unarchived"
}
} else if itemName == "CategoryList" {
if let jsonData = NSKeyedUnarchiver.unarchiveObject(withFile: addressPath) as? Data {
if let address = try? JSONDecoder().decode(Address.self, from: jsonData) {
streetLabel.text = address.street
houseLabel.text = String(address.house)
} else {
streetLabel.text = "NOT decoded"
houseLabel.text = "NOT decoded"
}
} else {
streetLabel.text = "NOT unarchived"
houseLabel.text = "NOT unarchived"
}
}
}
}
func isMetadataItemDownloaded(item : NSMetadataItem) -> Bool {
if item.value(forAttribute: NSMetadataUbiquitousItemDownloadingStatusKey) as? String == NSMetadataUbiquitousItemDownloadingStatusCurrent {
return true
} else {
return false
}
}
@IBAction func saveButtonPressed(_ sender: UIButton) {
let container = filesCoordinator.iCloudContainer
let personPath = filesCoordinator.getFilePath(container: container!, fileName: "TaskList")
let addressPath = filesCoordinator.getFilePath(container: container!, fileName: "CategoryList")
let person = Person(name: nameTextField.text!, weight: Double(weightTextField.text!)!)
let jsonPersonData = try? JSONEncoder().encode(person)
NSKeyedArchiver.archiveRootObject(jsonPersonData!, toFile: personPath)
let address = Address(street: streetTextField.text!, house: Int(houseTextField.text!)!)
let jsonAddressData = try? JSONEncoder().encode(address)
NSKeyedArchiver.archiveRootObject(jsonAddressData!, toFile: addressPath)
}
}//结束class
应用程序使用iCloud存储符合Codable协议的对象NSKeyedArchiver/NSKeyedUnarchiver。 设备之间的同步是可以的,除非在设备上重新安装应用程序(或安装在新设备上)并且包含数据的文件存在 - 在这种情况下 NSKeyedUnarchiver.unarchiveObject(withFile: filePathe) return 无。 当我在新设备上安装应用程序(在同一设备上重新安装)时,如何从 iCloud 的现有文件中获取数据?
class ViewController: UIViewController {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var weightLabel: UILabel!
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var weightTextField: UITextField!
var iCloudContainer: URL? {
return FileManager().url(forUbiquityContainerIdentifier: nil)
}
func getFilePath(container: URL, fileName: String) -> String {
let filePath = container.appendingPathComponent(fileName).path
return filePath
}
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func fetchButtonPressed(_ sender: UIButton) {
let container = self.iCloudContainer
let filePathe = getFilePath(container: container!, fileName: "Person")
if let jsonData = NSKeyedUnarchiver.unarchiveObject(withFile: filePathe) as? Data {
if let person = try? JSONDecoder().decode(Person.self, from: jsonData) {
nameLabel.text = person.name
weightLabel.text = String(person.weight)
} else {
nameLabel.text = "No data loaded"
weightLabel.text = "No data loaded"
}
} else {
nameLabel.text = "No data loaded"
weightLabel.text = "No data loaded"
}
}
@IBAction func saveButtonPressed(_ sender: UIButton) {
let container = self.iCloudContainer
let filePathe = getFilePath(container: container!, fileName: "Person")
let person = Person(name: nameTextField.text!, weight: Double(weightTextField.text!)!)
let jsonData = try? JSONEncoder().encode(person)
NSKeyedArchiver.archiveRootObject(jsonData!, toFile: filePathe)
}
要将数据从 iCloud 容器获取到本地 Ubiquity 容器,您应该使用元数据从 iCloud 查找项目并将其下载到设备。
lazy var metadataQuery : NSMetadataQuery = {
let query = NSMetadataQuery()
query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
query.predicate = NSPredicate(format: "%K CONTAINS %@", NSMetadataItemFSNameKey, "List")
NotificationCenter.default.addObserver(self, selector: #selector(didFinishGathering), name: NSNotification.Name.NSMetadataQueryDidUpdate, object: query)
NotificationCenter.default.addObserver(self, selector: #selector(didFinishGathering), name: NSNotification.Name.NSMetadataQueryDidFinishGathering, object: query)
return query
}()
override func viewDidLoad() {
super.viewDidLoad()
self.metadataQuery.start()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func didFinishGathering(notification: Notification?) {
let query = notification?.object as? NSMetadataQuery
query?.enumerateResults { (item: Any, index: Int, stop: UnsafeMutablePointer<ObjCBool>) in
let metadataItem = item as! NSMetadataItem
if isMetadataItemDownloaded(item: metadataItem) == false {
let url = metadataItem.value(forAttribute: NSMetadataItemURLKey) as! URL
try? FileManager.default.startDownloadingUbiquitousItem(at: url)
}
}
guard let queryresultsCount = query?.resultCount else { return }
for index in 0..<queryresultsCount {
let item = query?.result(at: index) as? NSMetadataItem
let itemName = item?.value(forAttribute: NSMetadataItemFSNameKey) as! String
let container = filesCoordinator.iCloudContainer
let filePath = filesCoordinator.getFilePath(container: container!, fileName: "TaskList")
let addressPath = filesCoordinator.getFilePath(container: container!, fileName: "CategoryList")
if itemName == "TaskList" {
if let jsonData = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Data {
if let person = try? JSONDecoder().decode(Person.self, from: jsonData) {
nameLabel.text = person.name
weightLabel.text = String(person.weight)
} else {
nameLabel.text = "NOT decoded"
weightLabel.text = "NOT decoded"
}
} else {
nameLabel.text = "NOT unarchived"
weightLabel.text = "NOT unarchived"
}
} else if itemName == "CategoryList" {
if let jsonData = NSKeyedUnarchiver.unarchiveObject(withFile: addressPath) as? Data {
if let address = try? JSONDecoder().decode(Address.self, from: jsonData) {
streetLabel.text = address.street
houseLabel.text = String(address.house)
} else {
streetLabel.text = "NOT decoded"
houseLabel.text = "NOT decoded"
}
} else {
streetLabel.text = "NOT unarchived"
houseLabel.text = "NOT unarchived"
}
}
}
}
func isMetadataItemDownloaded(item : NSMetadataItem) -> Bool {
if item.value(forAttribute: NSMetadataUbiquitousItemDownloadingStatusKey) as? String == NSMetadataUbiquitousItemDownloadingStatusCurrent {
return true
} else {
return false
}
}
@IBAction func saveButtonPressed(_ sender: UIButton) {
let container = filesCoordinator.iCloudContainer
let personPath = filesCoordinator.getFilePath(container: container!, fileName: "TaskList")
let addressPath = filesCoordinator.getFilePath(container: container!, fileName: "CategoryList")
let person = Person(name: nameTextField.text!, weight: Double(weightTextField.text!)!)
let jsonPersonData = try? JSONEncoder().encode(person)
NSKeyedArchiver.archiveRootObject(jsonPersonData!, toFile: personPath)
let address = Address(street: streetTextField.text!, house: Int(houseTextField.text!)!)
let jsonAddressData = try? JSONEncoder().encode(address)
NSKeyedArchiver.archiveRootObject(jsonAddressData!, toFile: addressPath)
}
}//结束class