SwiftUI + DocumentGroup в iOS / iPadOS: как переименовать текущий открытый документ
Мой вопрос касается DocumentGroup SwiftUI: используя простой проект на основе шаблона в Xcode (с использованием нового многоплатформенного шаблона приложения на основе документов), я могу создавать новые документы, редактировать их и т. Д. Кроме того, "вне" приложения , Я могу управлять файлом документа как таковым - перемещать его, копировать, переименовывать и т. Д.
По умолчанию все новые документы инициализируются именем «Без названия»; в основной точке входа приложения я могу получить доступ к URL-адресу файла:
var body: some Scene {
DocumentGroup(newDocument: ShowPLAYrDocument()) { file in
// For example, this gives back the actual doc file URL:
let theURL = file.fileURL
ContentView(document: file.$document)
}
}
Первый вопрос: как я могу отредактировать / изменить фактическое имя файла, когда документ «открыт», то есть когда код выполняется в области видимости
ContentView
? Отсутствие документации для SwiftUI очень затрудняет поиск ответов на подобные проблемы - я думаю, что обрушился на весь Интернет, но похоже, что ни у кого нет таких проблем, и если они есть, на их опубликованные вопросы нет ответов. - Я сам задал пару вопросов по другим вопросам, но даже комментариев не получил, не говоря уже об ответах.
У меня есть еще один вопрос, который, как мне кажется, в какой-то степени связан: я видел, например, в приложении «Файлы», что некоторые типы файлов, если они выбраны, могут отображать дополнительную расширенную информацию на панели «ИНФОРМАЦИЯ» для этого файла (например: видео файлы показывают размеры в пикселях, продолжительность и информацию о кодеке); документы моего приложения содержат несколько значений (в сохраненных данных), которые я хотел бы, чтобы пользователь мог "заглянуть" в средство выбора документов, не открывая файл как таковой, аналогично тому, как описано для приложения "Файлы"..
Мой второй вопрос: возможно ли это сделать, и если да, то где мне хотя бы начать искать ответы?Я предполагаю, что это «невозможно» с SwiftUI как таковым прямо сейчас, поэтому это должна быть интеграция с «обычным» Swift?
Заранее благодарим за любые рекомендации.
4 ответа
Проблемы, возникшие с указанным выше "решением", были связаны с (подтвержденной) ошибкой в
.fileImporter
модификатор - итак, это "работает", как бы хакерское оно есть.
Хорошо, вот в чем дело: мне «вроде как» удалось добиться того, чего я хотел, хотя это не выглядит (для меня) как самый «правильный» способ сделать это, И все еще есть проблема с процессом - хотя на данный момент я виню в этом (очевидно, известную) реализацию с ошибками, которая также вызывает другие проблемы ( см. этот вопрос для получения более подробной информации по проблеме).
Мне "вроде как" удалось изменить имя файла, как в следующем коде:
@main
struct TestApp: App {
@State var previousFileURL: String = ""
var body: some Scene {
DocumentGroup(newDocument: TestDocument()) { file in
ContentView(document: file.$document)
.onAppear() {
previousFileURL = file.fileURL!.path
}
.onDisappear() {
let newFileName = "TheNewFileName.testDocument"
let oldFileName = URL(fileURLWithPath: previousFileURL).lastPathComponent
var newURL = URL(fileURLWithPath: previousFileURL).deletingLastPathComponent()
newURL.appendPathComponent(newFileName)
do {
try FileManager.default.moveItem(atPath: oldURL.path, toPath: newURL.path)
} catch {
print("Error renaming file! Threw: \(error.localizedDescription)")
}
}
}
}
}
Что он делает: он "сохраняет" начальный URL-адрес документа в переменной состояния сразу после инициализации представления (в
ВОПРОСЫ
В настоящее время это очень неприятная проблема: при определенных обстоятельствах (то есть, когда приложение только что запущено и новый документ был создан с помощью кнопки «плюс»), код ведет себя так, как я и ожидал - он открывает новый документ, в котором я могу (с помощью «представления содержимого») редактировать (и сохранять) строку, которая станет именем файла, и когда я «закрываю ее» (с помощью кнопки «Назад» в NavigationView), он обновляет подходящее имя файла, что я могу подтвердить, фактически просмотрев файл в браузере документов.
НО ... если я повторно открываю тот же файл или работаю с другим файлом, или просто выполняю весь процесс создания нового файла и т.д. снова БЕЗ закрытия приложения, то, по-видимому,
Это происходит ДАЖЕ, если я проверю наличие файла со старым именем: когда он попадает в эти условия,
Надеюсь, это укажет кому-то с большим опытом и пониманием на лучший ответ, которым они (надеюсь) поделятся здесь.
Вы тестировали это "хакерское" решение на устройстве? Он хорошо работает на Simulator, но из-за новых правил разрешения доступа в iOS 13 код выдает
“XXXXXX” couldn’t be moved because you don’t have permission to access “YYYYYY”.
Так что да, очевидно, вы даже не можете переименовать файлы в папке, созданной приложением SwiftUI. Я еще не пробовал это в новом Swift UI (iOS14).
Вы тестировали вышеупомянутое "хакерское" решение на устройстве? Он хорошо работает на Simulator, но из-за новых правил разрешения доступа в iOS 13 код выдает
“XXXXXX” couldn’t be moved because you don’t have permission to access “YYYYYY”.
Я покопался глубже и попробовал перезаписать стандартную
init()
и определения функций
Document.swift
стандартный код, сгенерированный XCode, чтобы установить желаемое имя файла на
preferredFilename
а также
filename
свойства :
struct SomeDocument: FileDocument, Decodable, Encodable {
static var readableContentTypes: [UTType] { [.SomeDocument] }
var someData: SomeCodableDataType
init() {
self.someData = SomeCodableDataType()
print("Creating.\n")
}
init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents else {
throw CocoaError(.fileReadCorruptFile)
}
let savedPreferredName = configuration.file.preferredFilename
let savedName = configuration.file.preferredFilename
let fileRep = try JSONDecoder().decode(Self.self, from: data)
self.someData = fileRep.someData
print("Loading.\n Filename: \(savedPreferredName ?? "none") or \(savedName ?? "none")\n")
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
do {
let fileRep = try JSONEncoder().encode(self)
let fileWrapper = FileWrapper.init(regularFileWithContents: fileRep)
fileWrapper.preferredFilename = fileName()
fileWrapper.filename = fileName()
print("Writing.\n Filename \(fileWrapper.preferredFilename ?? "none") or \(fileWrapper.filename ?? "none").\n")
return fileWrapper
} catch {
throw CocoaError(.fileReadCorruptFile)
}
}
func fileName() -> String {
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "yyMMdd'-'HH:mm"
let timeStamp = timeFormatter.string(from: Date())
let extention = ".ext"
let newFileName = timeStamp + "-\(someData.someUniqueValue())" + extention
return newFileName
}
}
Вот распечатка консоли. Я добавил действия пользователя в скобки []:
[CREATE DOC BY TAPPING +]
Creating.
[AUTOMATIC WRITE]
Writing.
Filename 210628-16:49-SomeUniqueValue.ext or 210628-16:49-SomeUniqueValue.ext.
[AUTOMATIC LOAD]
Loading.
Filename: none or none
FileURL: /Users/bora/Library/Developer/CoreSimulator/Devices/F126086A-A752-4A71-B589-1B37DFC02746/data/Containers/Data/Application/D81C9D76-7986-4C0D-BA2C-1FDF69703875/Documents/Untitled 2.ext
isEditable: true
[CLOSING DOC]
Writing.
Filename 210628-16:49-SomeUniqueValue.ext or 210628-16:49-SomeUniqueValue.ext.
[REOPENING DOC]
Loading.
Filename: none or none
FileURL: /Users/bora/Library/Developer/CoreSimulator/Devices/F126086A-A752-4A71-B589-1B37DFC02746/data/Containers/Data/Application/D81C9D76-7986-4C0D-BA2C-1FDF69703875/Documents/Untitled 2.ext
isEditable: true
Итак, после первоначального создания документа первая запись (с
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper
), имя файла присвоено правильно. Однако, когда код представления загружает документ, становится ясно, что ни одно из свойств имени файла не было использовано. То же самое повторяется, когда документ закрывается (запись с назначенными именами) и открывается снова.
Это похоже на ошибку. Я не понимаю, почему DocumetGroup не использует свойства имени файла, определенно используя содержимое данных, предоставленное тем же
FileWrapper
.
Я еще не пробовал это на новом SwiftUI (iOS14). Я сделаю и доложу.
ОБНОВЛЕНИЕ: Протестировано на iOS 14, там тоже не работает. Полагаю, пора радар.