Почему я не могу повторно сохранить документ Core Data после сохранения, закрытия и повторного открытия документа? - PullRequest
0 голосов
/ 06 мая 2020

Проблема: Я создаю приложение Core Data на основе документов для Ma c, используя NSPersistentDocument. Поскольку я использую внешнее хранилище SQLite, каждый раз, когда я сохраняю документ, основной файл сохраняется как filename.sqlite. Но иногда я также вижу два вспомогательных файла SQLite, filename.sqlite-wal и filename.sqlite-shm, рядом с основным файлом. Это не очень удобно для пользователя.

Использование пакета документов: Вместо этого я пытаюсь использовать пакет документов, чтобы пользователь видел только filename.myCustomExtension в Finder. Чтобы выполнить sh это, я сохраняю файл внешнего хранилища как filename.sqlite внутри каталога (пакета документов), который я создаю непосредственно заранее, с именем filename.myCustomExtension, который в основном представляет собой просто папку. Для конечного пользователя, конечно, эта папка (документ) будет отображаться как один файл, на который можно щелкнуть.

Мои настройки: macOS 10.14.6 и Xcode 11.3.1 (11C504) с Swift 5. Чтобы создать свой проект Xcode, я использую шаблон Xcode Core Data на основе документа и заменяю read(from:ofType:) и writeSafely(to:ofType:for:). Сам шаблон создает для вас подкласс NSPersistentDocument, называемый Document, в который я помещаю эти переопределения. Насколько я могу судить, я правильно экспортировал и принял пользовательский UTI для моего нового типа документа в Info.plist.

Чтение: Чтобы читать в документе с моим расширением, я отменяю read(from:ofType:) и измените параметр absoluteURL с /Users/Mark/Desktop/filename.myCustomExtension/ на /Users/Mark/Desktop/filename.myCustomExtension/filename.sqlite. (Это позволяет моему приложению читать в фактическом файле .sqlite вместо его каталога оболочки.) Затем я вызываю метод super с новым путем к файлу:

override func read(from absoluteURL: URL, ofType typeName: String) throws {

    // Isolate the filename without any extension.
    let filename = absoluteURL.deletingPathExtension().lastPathComponent

    // Put together the new URL.
    let newAbsoluteURL = absoluteURL.appendingPathComponent(filename, isDirectory: false).appendingPathExtension("sqlite")

    // Read the .sqlite file inside the package.
    try super.read(from: newAbsoluteURL, ofType: typeName)
}

Запись: Чтобы сохранить документ, я аналогичным образом заменяю writeSafely(to:ofType:for:) указанием внутри каталога пакета и затем вызываю super. Для нового документа я сначала создаю каталог пакета. Для существующего документа этот шаг просто завершается неудачно, и выполнение переходит к следующей строке:

override func writeSafely(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType) throws {

    // Isolate the filename without any extension.
    let userChosenFilename = url.deletingPathExtension().lastPathComponent

    // Put together the new URL.
    newURL = url.appendingPathComponent(userChosenFilename, isDirectory: false).appendingPathExtension("sqlite")

    // Create the shell directory, if it isn’t already there.
    do {
        try FileManager.default.createDirectory(at: url, withIntermediateDirectories: false, attributes: nil)
    } catch {
        Swift.print("The document package already exists.")
    }

    // Write the .sqlite file inside the package.
    do {
        try super.writeSafely(to: newURL, ofType: typeName, for: saveOperation)
    } catch {
        Swift.print("writeSafely couldn’t write where I intended to.")
        Swift.print(error)
    }
}

Как это работает сейчас: Приложение создает новый документ и сохраняет его, как ожидалось . Внешнее хранилище .sqlite (называемое filename.sqlite) находится внутри пакета документов (называемого filename.myCustomExtension), что и видит пользователь. После того, как я выйду из приложения и перезапущу его, он без проблем прочитает только что созданный файл. Но когда я пытаюсь повторно сохранить файл, я получаю следующее сообщение об ошибке:

Error Domain = NSCocoaErrorDomain Code = 512 «Файл« filename.myCustomExtension »не может быть сохранен в папке« Desktop » »." UserInfo = {NSURL = file: ///Users/Mark/Desktop/filename.myCustomExtension/, reason = Нет известного постоянного хранилища для URL}

Аналогично, после повторного открытия документа Autosave завершается ошибкой

Установить URL-адрес файла напрямую? Возможно, после первоначального сохранения приложение использует свойство документа fileURL в качестве места сохранения и игнорирует мой переданный url параметр. Но если я попытаюсь установить свойство документа fileURL напрямую, я получаю ошибки.

Невозможно использовать NSFileWrapper: Я не использовал NSFileWrapper, потому что (1) кажется, что излишество для простого помещения одного файла в каталог, и (2) документация для NSPersistentDocument конкретно заявляет, что NSPersistentDocument не поддерживает файловые оболочки.

Это должно быть обычным явлением для разработчикам, чтобы скрыть внутреннюю работу SQLite от конечного пользователя, но я не могу заставить свой код работать. Ты можешь? ?

...