
アプリを作っていると、「このデータを別の画面や別のアプリに渡したい」という場面がよくあります。
例えば、
- 写真をドラッグ&ドロップで他のアプリに渡す
- 自作データをコピー&ペーストできるようにする
- 作った文章や画像を「共有」メニューから送る
こうした処理を、安全・シンプル・型安全に書けるのが Transferable プロトコルです。
Transferableプロトコルとは?
Transferableは、「この型のデータを外部に渡す方法」を決めるためのプロトコルです。
一言でいえば、SwiftUIでドラッグ&ドロップや共有を“型そのまま”で扱えるようにする仕組みです。
普通、アプリ間でやり取りするにはデータをData
やString
に変換したり、NSItemProvider
を直接触る必要がありますが、Transferableを使えばもっとシンプルに書けます。
どう書くの?
Transferableを使うには、その型に「どんな形でやり取りするか」を宣言します。
それがTransferRepresentation
です。
TransferRepresentation
は、Transferable
プロトコルの中で「この型をどういう形式でやり取りするか」を定義する部分です。
static var transferRepresentation
という形で指定します。
代表的なやり取り方法は次のとおりです。
TransferRepresentation | 役割 |
---|---|
CodableRepresentation | Codable準拠のデータを安全にやり取り |
DataRepresentation | Data + ファイル形式(例 .png 、.plainText )で転送 |
FileRepresentation | 大きなデータを一時ファイルで渡す |
ProxyRepresentation | 別のTransferableなプロパティを経由して渡す |
代表的な TransferRepresentation の種類と役割
ここでは、「この型をどういう形式でやり取りするか」を定義するTransferRepresentationの代表的な4種類を説明します。
1. CodableRepresentation
役割:Codable
に準拠したデータを安全にそのままやり取りします。
特徴:
- アプリ内や同じ型同士の受け渡しに最適
- モデル全体を完全復元できる
- 他アプリは
Codable
を理解できないので、互換性は限定的
2. DataRepresentation
役割:Data
とファイル形式(UTType)を組み合わせて転送します。
特徴:
- 画像(
.png
)、テキスト(.plainText
)など汎用的な形式にできる - 他アプリとの互換性が高い
- 必要に応じてエンコード・デコード処理を自分で書く
3. FileRepresentation
役割:大きなデータを一時ファイルとしてやり取りします。
特徴:
- 数百MB以上の動画や大きなJSONなど、メモリに載せにくいデータ向け
- 高速かつメモリ効率が良い
- 一時ファイルは受信後に保存先へ移動する必要あり
4. ProxyRepresentation
役割:既にTransferable
対応済みの別プロパティに処理を委譲します。
特徴:
- 共通化でコード重複を減らせる
- 基本的なやり取りは委譲先の型が担う
- 代表データ側の仕様変更が委譲元すべてに影響する
この4つを組み合わせることで、「まずは完全復元、ダメなら汎用形式、それもダメならファイル渡し」といった多段フォールバックが可能になります。
具体例でTransferableプロトコルを理解する
それでは「メモ(文字列)」をアプリ間・UI間でやり取りできるようにする具体例でTransferableプロトコルの具体例を見ていきましょう。
1. データ型(Note)の定義
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import SwiftUI import UniformTypeIdentifiers struct Note: Identifiable, Hashable, Codable, Transferable { var id = UUID() var text: String static var transferRepresentation: some TransferRepresentation { // 同型間で安全にやり取り(完全復元) CodableRepresentation(contentType: .data) // 他アプリともやり取りできるようプレーンテキスト形式も用意 DataRepresentation(exportedContentType: .plainText) { note in Data(note.text.utf8) } importing: { data in Note(text: String(decoding: data, as: UTF8.self)) } } } |
何をしようとしているか
Note
というメモを表す型を作り、それをTransferable対応にしています。- これにより、UI側で
Note
をそのまま共有したり、ドラッグできるようになります。
コードの意図
CodableRepresentation
- 同じアプリや同じ型間でのやり取りなら、
Note
を完全な形で安全に送受信できます。
- 同じアプリや同じ型間でのやり取りなら、
DataRepresentation(.plainText)
- 他のアプリは
Note
型を知らないため、代わりにプレーンテキストとしてやり取りできるようにフォールバック形式を用意。
- 他のアプリは
ポイント
- 複数の
TransferRepresentation
を組み合わせることで、アプリ間の互換性が上がります。 - 先に書いた形式が優先されます(ここではまず
Codable
、次に.plainText
)。
2. 共有(ShareLink)
1 2 3 4 5 6 7 8 9 10 |
struct ShareNoteButton: View { let note = Note(text: "こんにちは Transferable!") var body: some View { ShareLink(item: note) { Label("このメモを共有", systemImage: "square.and.arrow.up") } } } |
何をしようとしているか
note
をiOSの共有メニュー(AirDrop、メール、ファイル保存など)で送れるようにする。
コードの意図
ShareLink(item:)
にNote
を直接渡すと、システムがtransferRepresentation
を参照し、最適な形式(Codable or plainText)でエクスポートします。
ポイント
- UIコードが非常に短い:共有のために型変換やバイト列処理を一切書く必要がない。
- 拡張性:
Note
の転送方法を変えたい場合はNote
側のtransferRepresentation
を修正するだけでOK。
3. ドラッグ&ドロップ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
struct NotesBoard: View { @State private var notes = [ Note(text: "りんご"), Note(text: "バナナ"), Note(text: "みかん") ] @State private var dropped: [Note] = [] var body: some View { HStack(spacing: 24) { // ドラッグ元 VStack { Text("ドラッグ元").font(.headline) ForEach(notes) { note in Text(note.text) .padding(8) .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 8)) .draggable(note) // ← Transferable準拠のnoteを直接渡せる } } // ドロップ先 VStack { Text("ドロップ先").font(.headline) ForEach(dropped) { note in Text("受領: \(note.text)") .padding(8) .background(Color.green.opacity(0.2), in: RoundedRectangle(cornerRadius: 8)) } } .frame(minWidth: 200, minHeight: 180) .dropDestination(for: Note.self) { items, _ in dropped.append(contentsOf: items) return true } } .padding() } } |
何をしようとしているか
- 左側の「ドラッグ元」から、右側の「ドロップ先」に
Note
を直接ドラッグ&ドロップする機能を作る。
コードの意図
.draggable(note)
- ユーザーが要素をドラッグしたときに、その
note
をtransferRepresentation
に沿ってエクスポートします。
- ユーザーが要素をドラッグしたときに、その
.dropDestination(for: Note.self)
- ドロップされたデータを
Note
型として受け取り、配列dropped
に追加。
- ドロップされたデータを
ポイント
- 型変換不要:受け取り側で
Data
やString
への変換をしなくても直接Note
として扱える。 - 複数ドロップ対応:
items
は配列なので、複数のメモをまとめてドロップできる。 - アプリ間連携も可能:
plainText
のDataRepresentationを用意しておけば、他のアプリにドラッグしてもテキストとして受け取ってもらえる。
まとめ
Transferableは、「UI間やアプリ間でデータを渡す」処理を、短く安全に書ける仕組みです。
特にドラッグ&ドロップや共有機能を実装する際には非常に便利なので、「自作型を別の画面やアプリで使えるようにしたい」ときはまず検討すべき機能です。