ios - para - documents by readdle
UIDocument no se guarda en el archivo a pesar de indicar el éxito (3)
Estoy intentando abrir, modificar y guardar un archivo en iCloud Drive utilizando UIDocument
. Cuando llamo a save(to:for:completionHandler:)
con la ubicación del archivo y utilizando .forOverwriting
para UIDocumentSaveOperation
, se completa con el estado de success = true
. Sin embargo, el archivo de iCloud (como se ve en el navegador de escritorio de iOS y en el de escritorio) no se actualiza, y al volver a abrir el archivo, no se muestran los cambios. He verificado que el contents(forType:)
devuelve el contenido del archivo correcto (modificado) al guardar.
(Nota: ya he mirado esta pregunta , pero no fue muy útil 😕)
Aquí están las secciones relevantes del código:
MainViewController.swift:
var saveFile: SBDocument?
@IBAction func bbiOpen_pressed(_ sender: UIBarButtonItem) {
if saveFile == nil {
let importMenu = UIDocumentMenuViewController(documentTypes: self.UTIs, in: .import)
importMenu.delegate = self
importMenu.popoverPresentationController?.barButtonItem = bbiOpen
self.present(importMenu, animated: true, completion: nil)
} else {
willClose()
}
}
func willClose(_ action: UIAlertAction?) {
if saveFile!.hasUnsavedChanges {
dlgYesNoCancel(self, title: "Save Changes?", message: "Would you like to save the changes to your document before closing?", onYes: doSaveAndClose, onNo: doClose, onCancel: nil)
} else {
doSaveAndClose(action)
}
}
func doSaveAndClose(_ action: UIAlertAction?) {
saveFile?.save(to: saveFileURL!, for: .forOverwriting, completionHandler: { Void in
self.saveFile?.close(completionHandler: self.didClose)
})
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
saveFile = SBDocument(fileURL: url)
saveFile!.open(completionHandler: { success in self.finishOpen(didCompleteSuccessfully: success) })
}
func finishOpen(didCompleteSuccessfully result: Bool) {
if result {
print(saveFile!.localizedName)
saveFileURL = saveFile!.fileURL
saveFileName = saveFile!.localizedName
self.navTitleBar.prompt = saveFileName
bbiOpen.title = NSLocalizedString("titleClose", comment: "Close")
bbiOpen.style = .plain
} else {
saveFile = nil
}
}
@IBAction func bbiSave_pressed(_ sender: UIBarButtonItem) {
self.saveFile!.save(to: self.saveFileURL!, for: .forOverwriting, completionHandler: self.didSave)
}
func didSave(_ success: Bool) {
guard success else {
print("Error saving soundboard file to /(String(describing: saveFileURL))")
return
}
print("File saved successfully")
}
SBDocument.swift:
class SBDocument: UIDocument {
override var fileType: String? { get { return "com.whitehatenterprises.SoundBoardFX.sbd" } }
override var savingFileType: String? { get { return "com.whitehatenterprises.SoundBoardFX.sbd" } }
override init(fileURL url: URL) {
super.init(fileURL: url)
}
override func contents(forType typeName: String) throws -> Any {
let arr = NSArray(array: SoundEffects)
let data: NSData = NSKeyedArchiver.archivedData(withRootObject: arr) as NSData
return data
}
}
Actualización: realmente necesito ayuda con esto, y he intentado todo lo que se me ocurre para solucionarlo. Cualquier ayuda que me puedas dar sería muy apreciada.
Además de las respuestas anteriores, otra causa de esto puede ser que haya un error durante el proceso de guardado no relacionado con el contents(forType:)
.
Por ejemplo, si implementas fileAttributesToWrite(to:for:)
y fileAttributesToWrite(to:for:)
un error, esto puede provocar que UIDocumentState.savingError
, aunque el contents(forType:)
devuelva los datos correctos.
Así que de acuerdo con
https://developer.apple.com/reference/uikit/uidocument
Parece que la función de guardar no es realmente para guardar un documento. Mi comprensión al leerlo es que guardar es solo para crear un nuevo documento. Entiendo que está utilizando .forOverwriting para simplemente guardar sobre él, pero puede haber algo en iCloud que no permita que se realice la sobrescritura completa.
En su método doSaveAndClose intente llamar
self.saveFile?.close(completionHandler: self.didClose)
por sí mismo. Es posible que tenga que hacer algún tipo de consulta si comprueba si existe el archivo. Si no es así, llame a .save (), o llame a la función .close. Parece que no importa qué cuando el documento se cierra guarda los cambios.
La forma en que la generación de archivos inicial funciona para mí es:
let doc = YourUIDocumentClass(fileURL: fileURL)
doc.save(to: fileURL, for: .forCreating) { success in
...
}
Luego modifica el archivo y luego haz:
doc.save(to: fileURL, for: .forOverwriting) { success in
...
}
cuando termine. Y los accesos posteriores al archivo se realizan mediante:
doc.open() { success in
...
}
doc.close() { success in
...
}
También es posible que necesites hacer una
doc.updateChangeCount(.done)
Mientras el archivo está abierto para indicar al documento que hay cambios no guardados. Simplemente configurando esto se guardará después de unos segundos. Ni siquiera necesitas el cierre para hacer eso.
El ... significa que debe anidar todo esto o asegurarse de que haya suficiente tiempo entre ellos para que se completen.