はじめに (対象読者・この記事でわかること)

このページは、iOS アプリ開発に携わる Swift エンジニア、特に「UIDocumentPicker」を利用しようとしてコンパイルエラー
Cannot initialize a parameter of type 'id<UIDocumentPickerDelegate> _Nullable' with an lvalue of type 'const Class' に直面した方を対象としています。
記事を読み進めると、エラーの原因が「デリゲートの型指定ミス」や「クラス定義の書き方」にあることが分かり、正しいデリゲート設定のコードと、Xcode でのビルド回避手順が身につきます。また、同様の型エラー全般に応用できる Swift の型システムの基礎知識も復習でき、今後の開発で同種の問題に遭遇した際のトラブルシューティングがスムーズになるでしょう。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。
- Swift の基本的な文法とクラス/プロトコルの概念
- iOS アプリ開発における Xcode の基本操作
- UIDocumentPicker とそのデリゲートメソッドの概要

UIDocumentPicker とデリゲート設定の背景

UIDocumentPickerViewController は、ユーザーに外部ストレージや iCloud からファイルを選択させるための標準 UI コンポーネントです。利用するには、UIDocumentPickerDelegate プロトコルに準拠したオブジェクトをデリゲートとして設定する必要があります。多くのサンプルコードでは、self をそのまま渡す形が示されていますが、Swift と Objective‑C の相互運用が絡むと型推論が崩れ、上記のようなコンパイルエラーが発生します。

エラー文を分解すると次のようになります。

  • id<UIDocumentPickerDelegate> _Nullable … Objective‑C の「UIDocumentPickerDelegate プロトコルに準拠したオブジェクト」型
  • const Class … Swift 側で Class(メタタイプ)として扱っているが、const が付与されているため「インスタンス」ではなく「型」そのものを渡そうとしている

要するに、デリゲートに インスタンス を渡すべきところを クラスオブジェクト(メタタイプ)を渡していることが原因です。これが起きる典型的なシーンは、デリゲートクラスを static let shared = MyPickerDelegate.self のように .self を付けてしまう、あるいは MyPickerDelegate を直接 UIDocumentPickerViewController(delegate:) に渡すケースです。

正しい実装手順とコード例

以下では、エラーが再現しやすい「間違った書き方」と、正しく動作する「修正版」のコードをステップごとに比較しながら解説します。

ステップ 1 – デリゲートプロトコルを準拠したクラスを作成

Swift
import UIKit class DocumentPickerHandler: NSObject, UIDocumentPickerDelegate { // MARK: - UIDocumentPickerDelegate メソッド func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { // ユーザーが選択したファイルの URL 配列を処理 for url in urls { print("Picked file: \(url.lastPathComponent)") } } func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { print("Document picker was cancelled") } }

ポイントは NSObject を継承し、UIDocumentPickerDelegate に準拠させていることです。NSObject 継承は Objective‑C のランタイムに必要なブリッジングを提供します。

ステップ 2 – ビューコントローラでインスタンス化してデリゲートに設定

Swift
class ViewController: UIViewController { // デリゲートインスタンスをプロパティとして保持 private let pickerHandler = DocumentPickerHandler() @IBAction func openDocumentPicker(_ sender: UIButton) { // UIDocumentPickerViewController の初期化 let types: [UTType] = [UTType.content, UTType.item] // 任意のUTType let picker = UIDocumentPickerViewController(forOpeningContentTypes: types, asCopy: true) // 正しいデリゲート設定 picker.delegate = pickerHandler // ← インスタンスを渡す // 表示 present(picker, animated: true, completion: nil) } }

重要: picker.delegate = pickerHandler とし、インスタンス を渡す点です。.self を付けずにクラス名だけを渡すと先ほどのエラーになります。

ステップ 3 – 間違いやすいコード例とそのエラーメッセージ

Swift
// NG パターン: クラスオブジェクトを直接渡す picker.delegate = DocumentPickerHandler.self // ここがエラー原因

このコードをビルドすると、Xcode のコンパイル画面に次のように表示されます。

Cannot initialize a parameter of type 'id<UIDocumentPickerDelegate> _Nullable' with an lvalue of type 'const DocumentPickerHandler.Type'

ハマった点やエラー解決

1. .self の付与忘れ

多くの開発者が DocumentPickerHandler.self と書きがちです。Swift では型そのものを指すメタタイプになるため、デリゲートとしては不適格です。

2. プロパティが weak に設定されている

UIDocumentPickerViewControllerdelegateweak 参照です。デリゲートインスタンスがローカル変数だけで管理されると、スコープ外になった瞬間に解放されてしまい、実行時に delegatenil になるケースがあります。上記例では pickerHandler をビューコントローラのプロパティとして保持しているため、安全です。

3. NSObject 継承の抜け漏れ

UIDocumentPickerDelegate は Objective‑C のプロトコルです。Swift だけで実装すると、ランタイムがメソッドのシグネチャを認識できず、未実装メソッド の警告が出ます。NSObject を継承すれば Objective‑C ランタイムと正しく橋渡しできます。

解決策まとめ

項目 誤り例 正しい実装
デリゲート型 picker.delegate = DocumentPickerHandler.self picker.delegate = pickerHandler (インスタンス)
継承 class DocumentPickerHandler: UIDocumentPickerDelegate {} class DocumentPickerHandler: NSObject, UIDocumentPickerDelegate {}
インスタンス保持 ローカル変数で let handler = DocumentPickerHandler() ビューコントローラのプロパティ private let pickerHandler = DocumentPickerHandler()
メソッド実装 省略 documentPicker(_:didPickDocumentsAt:)documentPickerWasCancelled(_:) を必ず実装

上記表の通り、インスタンスを渡すNSObject 継承インスタンスを保持 の3点がエラー回避の鍵です。

まとめ

本記事では、Swift で UIDocumentPickerViewController のデリゲート設定時に発生するコンパイルエラー「Cannot initialize a parameter of type 'id _Nullable' with an lvalue of type 'const Class'」の原因と、正しい実装手順を具体例とともに解説しました。

  • 原因:デリゲートにクラスのメタタイプ(.self)を渡していたこと
  • 解決策NSObject 継承したデリゲートクラスのインスタンスを作成し、プロパティで保持した上で picker.delegate に設定する
  • ベストプラクティス:デリゲートは weak になるため、インスタンスが解放されないように参照を保持する

この記事を読むことで、同様の型エラーに遭遇した際にすぐに対処でき、iOS のファイルピッカー実装を安全かつスムーズに進められるようになります。次回は、UIDocumentPicker の新しい iOS 16 以降の API(UIDocumentPickerViewController(forOpeningContentTypes:asCopy:))と、マルチドキュメントサポートの実装例を取り上げる予定です。

参考資料