提问人:Patrick 提问时间:9/15/2022 最后编辑:Blazej SLEBODAPatrick 更新时间:11/18/2023 访问量:1346
SwiftUI ShareLink 设置文件名
SwiftUI ShareLink set file name
问:
我正在使用 来共享一个包含字符串的 String。符合协议。ShareLink
FileDocument
FileDocument
Transferable
这是 FileDocument 结构:
struct TransferableDocument: FileDocument, Transferable {
static var transferRepresentation: some TransferRepresentation
{
DataRepresentation(exportedContentType: .text) { log in
log.convertToData()
}
}
// tell the system to support only text
static var readableContentTypes: [UTType] = [.text]
// by default the document is empty
var text = ""
// this initializer creates a empty document
init(initialText: String = "") {
text = initialText
}
// this initializer loads data that has been saved previously
init(configuration: ReadConfiguration) throws {
if let data = configuration.file.regularFileContents {
text = String(decoding: data, as: UTF8.self)
}
}
// this will be called when the system wants to write the data to disk
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
let data = Data(text.utf8)
return FileWrapper(regularFileWithContents: data)
}
func convertToData() -> Data
{
return text.data(using: .ascii) ?? Data()
}
}
这就是 ShareLink:
var doc: TransferableDocument
{
return TransferableDocument(initialText: "I'm a String")
}
ShareLink(item: doc ,preview: SharePreview("logfile"))
{
Text("Share")
}
使用 AirDrop 时,文件名设置为 SharePreview 标题,在本例中为“logfile”。将其共享到“邮件”等应用程序时,文件名只需设置为“文本”。
有没有办法设置默认文件名?
答:
我们遇到了类似的问题,并在保存数据时配置了适当的文件名,并在 func 中添加了一个附加内容。这样一来,当共享到“邮件”时,就会使用适当的文件名。FileRepresentation
transferRepresentation
static var transferRepresentation: some TransferRepresentation
{
DataRepresentation(exportedContentType: .text) { log in
log.convertToData()
}
FileRepresentation(exportedContentType: .text) { log in
let fileURL = FileManager.default.temporaryDirectory.appendingPathComponent("logfile").appendingPathExtension("txt")
try log.convertToData().write(to: fileURL)
return SentTransferredFile(fileURL)
}
}
有一个方法:suggestedFileName
DataRepresentation(exportedContentType: .png) { layer in
layer.pngData()
}
.suggestedFileName("Layer.png")
更新1:
它现在正在使用 Xcode 14.3 和 FileRepresentation 进行编译。但是我无法在 iOS 16.0 模拟器上与 FileRepresentation 共享文件,所以我不知道它在 iOS 16.0 上是否有效,但它在 iOS 16.1 Simpulator 上有效。在macOS上,共享弹出窗口中没有“保存到文件”选项,因此我不知道它是否有效。 :(
我在评论中提到了 exportCondition 的一个错误,它在 iOS 16.4 和 macOS 13.3 上按预期工作。
更新2:
可转移协议仍未按预期工作。
- 如果有多个 FileRepresentation,并且其中一个具有 suggestedFileName,则将用于每个 FileRepresentation。即使带有 suggestedFileName 的 FileRepresentation 的 exportingCondition 返回 false。
- exportingCondition 不能与 Main Actor 隔离对象一起使用。
我认为建议的FileName也是无用的,因为无法确定可转移的对象(例如文档名称)。
评论
从 iOS 17 开始,这现在正在工作:
extension MyDocument: Transferable {
public static var transferRepresentation: some TransferRepresentation {
DataRepresentation(contentType: .foo) { document in
[...]
} importing: { data in
[...]
}
.suggestedFileName { document in
document.bar
}
}
}
下面是一个解决方案,它允许根据要共享的对象的内容动态设置文件名(在本例中为 SwiftData 类):
import CoreTransferable
import SwiftData
@Model
class Session: Codable, Transferable {
var startTime: Date? = Date.now
// conform to Codable
enum CodingKeys: String, CodingKey { ... }
required init(from decoder: Decoder) throws { ... }
func encode(to encoder: Encoder) throws { ... }
static var transferRepresentation: some TransferRepresentation {
let rep = DataRepresentation<Session>(exportedContentType: .json) { session in
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
return try! encoder.encode(session)
}
return rep.suggestedFileName { session in session.suggestedFileName }
}
var suggestedFileName: String { "Session on \(startTime!.ISO8601Format()).json" }
然后你可以简单地使用
ShareLink(
item: session,
preview: SharePreview(session.suggestedFileName)
)
以及共享表中的“预览名称”,并设置了实际文件名。
诀窍是显式设置 .DataRepresentation<Session>
评论