认识 Transferable 协议
Meet Transferable
2022年6月6日
一句话判断
Transferable 是 Apple 今年推出的统一数据传输协议,一行代码让你的自定义类型支持拖放、复制粘贴、ShareLink 分享,包括 watchOS 上的分享功能。
这场 Session 讲了什么
SwiftUI 工程师 Julia 以一个”女性计算机科学家名录”App 为案例,介绍了 Transferable 协议的设计和使用。
Transferable 是一个 Swift-first 的声明式协议,描述你的模型类型如何序列化和反序列化以支持跨进程数据传输。它统一了拖放、复制粘贴、ShareSheet 等多种数据传输场景的底层机制。标准类型(String、Data、URL、AttributedString、Image)已经内置支持。
三种核心表示方式:CodableRepresentation(基于 Codable 的序列化)、DataRepresentation(直接的 Data 转换)、FileRepresentation(基于文件的数据传输,适合大文件不加载到内存)。ProxyRepresentation 允许用其他 Transferable 类型代表你的模型。
值得深挖的点
三种表示方式的选择逻辑。 模型是 Codable 且没有特殊二进制格式要求?用 CodableRepresentation。有自定义二进制格式但数据量小?用 DataRepresentation。数据量大或已经在磁盘上?用 FileRepresentation,避免加载到内存。
ProxyRepresentation 的实用价值。 一个 Profile 类型可以同时提供 CodableRepresentation(供支持自定义 UTType 的 App 使用)和 ProxyRepresentation(作为 String 供任何文本框粘贴)。接收方会按顺序尝试,用第一个支持的表示方式。
ShareLink 首次让 watchOS 支持分享。 配合 Transferable 协议,watchOS 9 可以通过 ShareLink 分享内容。iOS 和 macOS 上的 ShareSheet 也获得了全新设计。
代码片段
// CodableRepresentation:最常用的表示方式
struct Profile: Codable, Transferable {
let id: UUID
let name: String
let bio: String
static var transferRepresentation: DataRepresentationTransferRepresentation<Profile> {
CodableRepresentation(contentType: .profile)
}
}
// DataRepresentation:自定义二进制格式
struct ProfilesArchive: Transferable {
let profiles: [Profile]
static var transferRepresentation: DataRepresentationTransferRepresentation<ProfilesArchive> {
DataRepresentation(contentType: .commaSeparatedText) { archive in
// 归档 → CSV Data
archive.csvData
} importing: { data in
// CSV Data → 归档
try ProfilesArchive(csvData: data)
}
}
}
// FileRepresentation:大文件不加载到内存
struct Video: Transferable {
let url: URL
static var transferRepresentation: some TransferRepresentation {
FileRepresentation(contentType: .movie) { video in
// 传递文件 URL,不加载内容到内存
SentTransferredFile(video.url)
} importing: { received in
Video(url: received.file)
}
}
}
// ProxyRepresentation:粘贴时显示为文本
struct Profile: Codable, Transferable {
let name: String
// ...
static var transferRepresentation: some TransferRepresentation {
CodableRepresentation(contentType: .profile)
// 粘贴到文本框时,显示 name
ProxyRepresentation { profile in
profile.name as String
}
}
}
最佳实践
- 表示方式的声明顺序很重要。 接收方按顺序尝试,第一个支持的就用。把最完整的表示放在前面,降级的放在后面。
- 自定义 UTType 需要在 Info.plist 和代码中同时声明。 添加声明和文件扩展名,确保系统知道你的 App 能打开这种文件。
- 大文件务必用 FileRepresentation。 视频等大文件如果用 DataRepresentation 会全部加载到内存,影响性能。
- 标准类型已内置 Transferable 支持。 String、URL、Image 等直接用于 ShareLink 和拖放,不需要额外代码。
还有什么值得关注
- Transferable 是
ShareLink、PasteButton、onCopyCommand等新 SwiftUI API 的底层协议 - 推荐观看 “Uniform Type Identifiers — A reintroduction” 深入理解 UTType
- “Meet Transferable” 和 “What’s new in SwiftUI” 搭配观看效果最佳
- watchOS 9 的分享能力是一个值得关注的平台扩展