Возникли проблемы при получении 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, тогда оно начнет работать, в моем случае. На реальном устройстве все работает без ошибок.

Другие вопросы по тегам