Возникли проблемы при получении UIDocumentBrowserController для открытия документов в приложении на основе документов
Я работал над новым приложением, основанным на Document, и был очень рад новому UIDocumentBrowserController... пытаться развернуть свое собственное решение для пользовательского интерфейса браузера документов было сложно!
У меня возникли проблемы с тем, чтобы браузер открывал документы после их создания.
Что происходит сейчас, так это то, что когда я выбираю создание нового документа в браузере документов, документ создается и открывается, как и ожидалось, хотя и регистрируется сообщение об ошибке. Однако после закрытия документа я не могу открыть файл ни сразу, ни при последующих запусках, даже если документ отображается. Однако странная подсказка заключается в том, что если я перестану запускать приложение после создания документа, но не добавлю в него новую информацию (запуск цикла сохранения), и снова запущу проект, я смогу правильно открыть файл. Что заставляет меня думать, что в способе сохранения файлов есть что-то, что является проблемой. (Примечание: на этом этапе я работаю над тем, чтобы работала локальная имплементация без /icloud, прежде чем перейти к реализации icloud.)
Вот сообщение об ошибке в любой точке кода, когда документ сохраняется на диск (или, по крайней мере, большую часть времени!): 2017-06-20 13:21:58.254938-0500 iOS Sermon Design 2 [22454:5000138] [ по умолчанию] [ОШИБКА] Не удалось получить значения атрибутов для файла элемента:/// Пользователи /stevenhovater/ Библиотека / Разработчик /CoreSimulator/ Устройства /9A4364F2-B3A1-4AD9-B680-FB4BC876C707/data/Containers/Data/Application/DD534ED8-C4A3-40FE-9777-AED961976878/ Документы / Без названия-9.sermon. Ошибка: Ошибка Domain=NSFileProviderInternalErrorDomain Code=1 "Читателю не разрешен доступ к URL-адресу". UserInfo={NSLocalizedDescription= Читателю не разрешен доступ к URL.}
Я подозреваю, что проблема заключается в списках типов документов, которые я пытался настроить, имитируя настройку в видео для сеанса wwdc 2017 года 229.
Мои документы инкапсулированы объектом NSData, используя то, что я считаю довольно стандартным подклассом UIDocument. (Я опускаю код для создания эскизов)
override func contents(forType typeName: String) throws -> Any {
print("Saving Document Changes")
if sermon != nil {
let newData = NSKeyedArchiver.archivedData(withRootObject: sermon!)
return newData
} else {
let newData = NSKeyedArchiver.archivedData(withRootObject: Sermon())
return newData
}
}
override func fileAttributesToWrite(to url: URL, for saveOperation: UIDocumentSaveOperation) throws -> [AnyHashable : Any] {
let thumbnail:UIImage = self.createThumbnail()
let thumbnaildict = [URLThumbnailDictionaryItem.NSThumbnail1024x1024SizeKey : thumbnail]
let dict = [URLResourceKey.thumbnailDictionaryKey:thumbnaildict]
return dict
}
override func load(fromContents contents: Any, ofType typeName: String?) throws {
guard let newSermon:Sermon = NSKeyedUnarchiver.unarchiveObject(with: contents as! Data) as? Sermon else{
throw documentErrors.invalidFile
}
self.sermon = newSermon
}
В моем подклассе UIDocumentBrowserViewController, Вот мой код для получения локального имени файла и для создания нового документа.
func documentBrowser(_ controller: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, UIDocumentBrowserViewController.ImportMode) -> Void) {
var newDocumentURL: URL? = nil
print("creating new local document")
guard let target = self.newLocalFilename() else {
return
}
let targetSuffix = target.lastPathComponent
let tempURL = URL(fileURLWithPath: NSTemporaryDirectory() + targetSuffix)
let newDocument:SDDocument = SDDocument(fileURL: tempURL)
newDocument.sermon = Sermon()
/
newDocument.save(to: tempURL, for: .forCreating) { (saveSuccess) in
/
guard saveSuccess else {
/
importHandler(nil, .none)
return
}
/
newDocument.close(completionHandler: { (closeSuccess) in
/
guard closeSuccess else {
/
importHandler(nil, .none)
return
}
/
importHandler(tempURL, .move)
})
}
}
func newLocalFilename() -> URL? {
let fileManager = FileManager()
guard let baseURL = self.localDocumentsDirectoryURL.appendingPathComponent("Untitled")
else {return nil}
var target = baseURL.appendingPathExtension(DocumentBrowserViewController.documentExtension)
var nameSuffix = 2
while fileManager.fileExists(atPath: target.path) {
target = URL(fileURLWithPath: baseURL.path + "-\(nameSuffix).\(DocumentBrowserViewController.documentExtension)")
nameSuffix += 1
}
let targetSuffix = target.lastPathComponent
print("Target name: \(targetSuffix)")
print("new url: \(target)")
return target
}
5 ответов
После четырех или пяти часов работы, ударившись головой об эту проблему, я обнаружил простое решение: не тестировать в симуляторе. Я переключился на тестирование на своем устройстве, и сразу все стало работать как рекламируется.
[Я не могу сказать из опыта здесь, но может быть, что проблема "не работает в симуляторе" ограничена Сьеррой, но что симулятор действительно работает в Высокой Сьерре. Это объясняет, почему некоторые пользователи видят эту проблему, а другие - нет, и особенно почему Apple, кажется, блаженно не знает об этом в видео WWDC.]
У меня была точно такая же проблема, когда я пытался сохранить в NSTemporaryDirectory()
,
Если вы вместо этого сохраните в каталог документов ([[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]
), похоже, работает нормально!
Обновление: похоже, эта проблема исправлена в iOS 11 beta 3, и теперь вы можете сохранять вновь созданные документы в NSTemporaryDirectory()
правильно.
Вот моя текущая теория.
Эта ошибка
Error Domain=NSFileProviderInternalErrorDomain Code=1 "The reader is not permitted to access the URL."
отображается при первом создании UIDocument по новому URL с использованием -initWithFileURL. По сути, он говорит: "Этот URL еще не существует", но таким образом, что это больше похоже на проблему с разрешениями.
Насколько я могу судить, это не мешает вам сохранять, открывать, редактировать или закрывать файл. Так что я думаю, что это просто лишняя ошибка, которую Apple должна была устранить.
Возникла похожая проблема, и попробовал метод для предоставления Базового Местоположения по умолчанию в настройках Схем, и теперь он работает. Метод был упомянут в этом ответе: IOS 9 Error Domain = kCLErrorDomain Code = 0 "(null)"
Я обнаружил, что ошибка происходит на симуляторе, когда LSSupportsOpeningDocumentsInPlace
свойство установлено в YES в info.plist. Превратите это свойство в NO, тогда оно начнет работать, в моем случае. На реальном устройстве все работает без ошибок.