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