UIDocument not saving to file despite indicating success

廉价感情. 提交于 2019-12-20 11:13:08

问题


I'm trying to open, modify, and save a file in iCloud Drive using UIDocument. When I call save(to:for:completionHandler:) with the file location and using .forOverwriting for the UIDocumentSaveOperation, it completes with a status of success = true. However, the iCloud file (as seen in both desktop and iOS file browser) does not update, and when reopening the file, the changes are not shown. I've verified that contents(forType:) returns the correct (modified) file contents when saving.

(Note: I've already looked at this question, but it wasn't very helpful 😕)

Here are the relevant sections of code:

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

Update: I really need help with this, and I've tried everything I can think of to fix this. Any assistance you could give me would be greatly appreciated.


回答1:


The way the initial file generation works for me is:

    let doc = YourUIDocumentClass(fileURL: fileURL) 
    doc.save(to: fileURL, for: .forCreating) { success in
        ...            
    }

Then modify the file and then do:

    doc.save(to: fileURL, for: .forOverwriting)  { success in
        ...            
    }

when done. And subsequent accesses to the file are done by:

    doc.open() { success in
        ...
    }

    doc.close() { success in
        ...            
    }

You might also need to do a:

    doc.updateChangeCount(.done)

while the file is open to tell the document there are unsaved changes. Just setting this will cause a save after a few seconds. You don't even need the close to do that.

The ... means that you either have to nest all these or make sure there is enough time between them so they are completed.




回答2:


In addition to the above answers, another cause of this can be that there's an error during the save process unrelated to contents(forType:).

For example, if you implement fileAttributesToWrite(to:for:) and throw an error, then this can cause a UIDocumentState.savingError even though contents(forType:) returns the correct data.




回答3:


So according to

https://developer.apple.com/reference/uikit/uidocument

It looks like the save function isn't actually for saving a document. My understanding from reading it is that save is only for creating a new document. I understand that you are using the .forOverwriting to just save over it but there may be something in iCloud that wont let the complete overwrite happen.

In your doSaveAndClose method try calling

self.saveFile?.close(completionHandler: self.didClose)

by itself. You may have to do some type of if query where you check if the file exist. If it doesn't then call the .save(), else call the .close function. It seems that no matter what when the document it closed it saves changes.



来源:https://stackoverflow.com/questions/43193010/uidocument-not-saving-to-file-despite-indicating-success

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!