UIDocument не сохраняет файл, несмотря на то, что он указывает на успех

Я пытаюсь открыть, изменить и сохранить файл в iCloud Drive с помощью UIDocument. Когда я вызываю save(to:for:completionHandler:) с расположением файла и используя .forOverwriting для UIDocumentSaveOperation, он завершает состояние success = true. Однако файл iCloud (как видно как в обозревателе обоев рабочего стола, так и в iOS) не обновляется, а при повторном открытии файла изменения не отображаются. Я подтвердил, что contents(forType:) возвращает правильное (измененное) содержимое файла при сохранении.

(Примечание: я уже рассмотрел этот вопрос, но это было не очень полезно 😕)

Вот соответствующие разделы кода:

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: Мне действительно нужна помощь в этом, и я пробовал все, что мог придумать, чтобы исправить это. Любая помощь, которую вы могли бы мне дать, была бы весьма признательна.

Ответы

Ответ 1

В дополнение к приведенным выше ответам, еще одной причиной этого может быть ошибка во время процесса сохранения, не связанная с contents(forType:).

Например, если вы реализуете fileAttributesToWrite(to:for:) и выбрасываете ошибку, это может вызвать UIDocumentState.savingError даже если contents(forType:) возвращает правильные данные.

Ответ 2

Итак, согласно

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

Похоже, что функция сохранения фактически не предназначена для сохранения документа. Я понимаю, что это только чтение нового документа. Я понимаю, что вы используете .forOverwriting, чтобы просто сохранить его, но в iCloud может быть что-то, что не позволит полностью перезаписать.

В вашем методе doSaveAndClose попробуйте позвонить

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

сам по себе. Возможно, вам придется выполнить какой-либо запрос, если вы проверяете, существует ли файл. Если это не так, то вызовите .save(), иначе вызовите функцию .close. Кажется, что независимо от того, когда документ закрыл, он сохраняет изменения.

Ответ 3

Способ создания исходного файла для меня:

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

Затем измените файл, а затем выполните:

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

когда закончите. И последующие обращения к файлу выполняются с помощью:

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

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

Вам также может потребоваться выполнить:

    doc.updateChangeCount(.done)

в то время как файл открыт для указания документа, есть несохраненные изменения. Просто установка этого приведет к сохранению через несколько секунд. Вам даже не нужно близко делать это.

Это означает, что вам либо нужно вложить все это, либо убедиться, что между ними достаточно времени, чтобы они были завершены.